java - java中可以为null的返回值是否可以放入kotlin中声明为非null的变量中
问题描述
作为一名 Kotlin 的新开发人员,我第一次遇到一个我很乐意得到解释的情况。View的findViewById方法可以返回 null (这是我作为 java 开发人员从知识中知道的,但我很高兴知道我是否可以理解仅根据方法签名可以返回 null 值,而无需打开 android 文档) 但是我'令我惊讶的是,编译器并没有阻止我将返回值分配给不可为空的 View 对象。它不应该阻止这项任务吗?ASAIK,以下作业将无法编译:
var str1 : String? = "just a string"
var str2: String = str1
那么区别是什么呢?
解决方案
Kotlin 的无效性检查是 kotlinc 的虚构。一旦生成了一个类文件,那个问号(或没有问号)就消失了。编译器没有线索。是的,方法签名具有此信息(如果您有一个文件:fun helloWorld(): String { return "Hello" }
,并编译它,然后编写其他调用helloWorld()
的代码,该代码知道 helloworld 函数已被声明为返回非空字符串,即使您没有源文件) - 但就 java-the-VM-executable 而言,这是一条注释。
这样,它与泛型完全相同。你可以这样做:
public void iWillMessYouUp(List<String> list) {
List raw = list; // this generates a warning, but compiles.
raw.add(5); // this compiles. I just added an Integer to a String list...
}
List<String> myList = new ArrayList<String>();
iWillMessYouUp(myList);
for (Integer i : myList) System.out.println(i);
该代码将在最后一行抛出 ClassCastException,这很有趣,因为该行没有强制转换。你会期望这raw.add(5)
条线会抛出一些东西,但事实并非如此,因为泛型是 javac 的虚构。如果 javac 没有在编译时阻止您,那么 java-the-vm 肯定也不会这样做。
那些空类型也是如此。它不是空检查。
但是请注意,kotlin 可能会注入带有 nullcheck 的显式代码,我不记得它是否为了 java 代码的利益而这样做。即这个kotlin代码:
fun say(in: String) {
println(in)
}
被翻译成伪代码:
METHOD say(Ljava/lang/String;)V {
if (in == null) throw new NullPointerException("in");
java.lang.System.out.println(in);
}
快速javap
了解 kotlinc 吐出的内容会告诉你它是否这样做。
这使我们陷入无效行为。
事实证明,有 4 种方法可以做泛型。要表示“数字列表”,有 4 种方法可以这样做:
List<Number> // invariant
List<? extends Number> // covariant
List<? super Number> // contravariant
List // raw
最后一个很棘手:它允许一切,并且有意(或多或少)让你破坏东西。它不一定存在,但它确实存在:在泛型存在之前就已经编写了代码,如果原始模式不可用,与遗留代码交互将是痛苦的。
Kotlin 以及所有各种基于注解的 Java 无效系统(它们与 kotlin 所做的一样好,实际上 - 工作原理相同),需要处理这样一个事实,即 95% 的社区代码在类文件形式不包含任何关于 nullity 的提示。因此,它需要被视为“遗产”。
kotlin 解决遗留问题的方式与 java 使用泛型解决遗留问题的方式非常相似:Anything goes。
如果您将遗留无效值分配给非 null 事物?'凯。Kotlin 假设您知道自己在做什么。它可以注入一个显式的空检查,但是到处都有很多空检查,太多了,这将对类大小和性能产生显着的影响。在旧版空参数的位置传递空值?'凯。显然那没关系,kotlin 不知道并遵从您的代码。
顺便说一句,即使没有遗产,也有 3 个无效,而不是 2 个这一事实应该告诉您,kotlin 的“事物要么可以为空,要么不能”被过度简化了,这意味着 kotlin 在这方面是不完整的。所以它是:不可能编写一个方法来接收 ?? 的列表。nullity 字符串并以任何方式适当地执行(因此您可以传入可空字符串或不可空字符串的列表,您的方法不在乎,同时您仍然可以获取(可空)字符串并添加 Xs,其中 X 是要么是已知的非空字符串,要么是从该列表中获得的(可能)空字符串。不变量、协变和逆变的概念往往适用于所有类型关系和标签,而空值与 ' 一样多是一个标签此列表包含字符串' 是一个。
推荐阅读
- python - 在 Python 中下载带有“urllib.request.urlretrieve”的图像失败
- angular - 如何以角度从 OwlDateTime 中删除 AM 和 PM(因为它已经是 24 小时格式)
- java - 无法打开使用 apache poi 创建的 xlsx 文件
- c++ - 编写时间代码使年利率翻倍
- node.js - 错误:使用 web3 签署交易时,给定输入“[object Object]”不是数字
- docker - 错误:获取通道的背书客户端时出错
- mdx - Olap异常:蒙德里安XML::没有函数匹配签名'Exists(
, )' - c - 为什么错误:当我尝试初始化结构变量时,会出现“{”标记之前的预期表达式
- scala - 数据框用唯一的纪元时间替换每一行空值
- android - 在导航抽屉中按下注销按钮后,Android 应用程序冻结