为什么 Kotlin 在一种情况下推断从 Java 返回的类型可以为 null,而在另一种情况下它可以是可为 null 或不可为 null?
我已经检查了两者HashMap.get,JsonNode.get而且我无法在 calsses 中或继承链中的任何位置识别任何类似 @NotNull 的注释。是什么让 Kotlin 以不同的方式对待这两个调用?
我已阅读文档https://kotlinlang.org/docs/java-interop.html#null-safety-and-platform-types但它解释使用“平台类型”,但没有解释这些是什么,也没有解释行为差异反正。
import com.fasterxml.jackson.databind.JsonNode
private fun docType(node: JsonNode, map: java.util.HashMap<String,String>) {
val x: JsonNode = node.get("doc_type") // DOES compile and can throw NPE at runtime
val y: JsonNode? = node.get("doc_type") // DOES compile and Kotlin's type system will force you to check for null
val z: String = map.get("a") // ERROR: Type mismatch: inferred type is String? but String was expected
}
Run Code Online (Sandbox Code Playgroud)
Kotlin 提供了与 Java 的无缝互操作性,几乎不影响其自身的空安全性。一个例外是 Kotlin 假定Java 中定义的所有类型都不为 null。
\n为了理解,让我们看看JsonNode.get()
public JsonNode get(String fieldName) { return null; }\nRun Code Online (Sandbox Code Playgroud)\n请注意,JsonNode是在 Java 中定义的,因此是一种平台类型- Kotlin 不会将其“翻译”为JsonNode?,即使这在技术上是正确的(因为在 Java 中所有类型都可为空)。
从 Kotlin 调用 Java 时,为了方便起见,假设平台类型不可为 null。如果不是这种情况,您将始终必须检查任何平台类型的任何实例是否不为空。
\n因此,要回答您关于“平台类型”是什么的问题,它是一个术语,意思是
\n<type>!例如,符号是String!- 我们可以将其理解为String or String?与 Kotlin 可空?符号最接近的 Java 等效项是可空性注释,Kotlin 编译器可以解析并考虑该注释。但是,没有一个用于JsonNode方法。所以 Kotlin 会很高兴地假设node.get("")会返回JsonNode,而不是JsonNode?。
正如您所指出的,没有为 定义HashMap.get(...)。
那么 Kotlin 如何知道map.get("a")返回可空类型呢?
类型推断无济于事。(Java) 方法签名
\npublic V get(Object key) {\n //...\n}\nRun Code Online (Sandbox Code Playgroud)\n表明 aHashMap<String, String>应该返回String,而不是String?。肯定还有其他事情发生...
对于大多数 Java 类型,Kotlin 将仅使用所提供的定义。但对于某些,Kotlin 决定特殊对待它们,并用自己的版本完全替换 Java 定义。
\n您可以在文档中查看映射类型的列表。虽然HashMap里面不存在,但Map确实存在。因此,当我们编写 Kotlin 代码时,HashMap不会继承java.util.Map- 因为它映射到kotlin.collections.Map
\n\n\n
因此,如果我们查看定义的get函数的代码kotlin.collections.Map,我们可以看到它返回一个可为空的值类型
/**\n* Returns the value corresponding to the given [key], or `null` if such a key is not present in the map.\n*/\npublic operator fun get(key: K): V?\nRun Code Online (Sandbox Code Playgroud)\n因此 Kotlin 编译器可以查看HashMap.get(...)并推断出,因为它正在实现kotlin.collections.Map.get(...),所以返回的值必须是可以为 null 的值,在我们的例子中是String?。
无论出于何种原因,杰克逊没有使用可以解决此问题的可为空注释。幸运的是,IntelliJ 提供了一种解决方法,虽然不那么严格,但会提供有用的警告:外部注释。
\n一旦我按照说明操作...
\n\n现在node.get("")将显示警告。
此注释对 Kotlin 编译器不可见,因此它只能是警告,而不是编译错误。
\n| 归档时间: |
|
| 查看次数: |
880 次 |
| 最近记录: |