gpt4 book ai didi

kotlin - 从 Kotlin 调用 Java 时的可空规则是什么

转载 作者:行者123 更新时间:2023-12-02 18:10:21 24 4
gpt4 key购买 nike

为什么 Kotlin 在一种情况下推断从 Java 返回的类型是可为空的,而在另一种情况下它可以是可空的或不可空的?

我已经检查了 HashMap.getJsonNode.get 并且我无法在 calsses 中或继承链中的任何地方识别任何类似 @NotNull 的注释。是什么让 Kotlin 以不同的方式处理这 2 个调用?

我已阅读文档 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
}

最佳答案

Kotlin 提供与 Java 的无缝互操作性,而不会损害其自身的空安全性……几乎。一个异常(exception)是 Kotlin 假定在 Java 中定义的所有类型都是非空的。

要理解,让我们看一下JsonNode.get()

平台类型

  public JsonNode get(String fieldName) { return null; }

请注意 JsonNode是用 Java 定义的,因此是 'platform type' - 并且 Kotlin 不会将其“翻译”为 JsonNode? ,即使这在技术上是正确的(因为在 Java 中所有类型都可以为空)。

从 Kotlin 调用 Java 时,for convenience假定平台类型不可为空。如果不是这种情况,您将总是必须检查任何平台类型的任何实例是否不为空。

因此,要回答您关于什么是“平台类型”的问题,这个术语意味着

  • 一些用外部目标语言定义的类型,
  • 您不能在 Kotlin 代码中明确提及它(但可能有一个同义的 Kotlin 等效项),
  • 为了方便起见,我们假设它不可为空。
  • 符号也是<type>! ,例如 String! - 我们可以理解为 String or String?

可空性注释

最接近 Kotlin 的可空 ? 的 Java 等价物符号是nullability annotations ,Kotlin 编译器可以解析和考虑。然而,JsonNode 上没有使用任何一个方法。所以 Kotlin 会很高兴地假设 node.get("")将返回 JsonNode , 不是 JsonNode? .

如您所述,HashMap.get(...) 没有定义.

那么 Kotlin 如何知道 map.get("a")返回可空类型?

类型推断

Type inference没办法。 (Java) 方法签名

public V get(Object key) {
//...
}

表示HashMap<String, String>应该返回 String , 不是 String? .一定有其他事情发生了......

映射类型

对于大多数 Java 类型,Kotlin 将只使用提供的定义。但对于一些,Kotlin 决定对它们进行特殊处理,并用自己的版本完全替换 Java 定义。

可以看到the list of mapped types in the docs .同时 HashMap不在那里,Map是。因此,当我们编写 Kotlin 代码时,HashMap不继承自 java.util.Map - 因为它映射到 kotlin.collections.Map

Aside: in fact if you try and use java.util.Map you'll get a warning code that uses java.util.Map with an IntelliJ warning: This class shouldn't be used in Kotlin. Use kotlin.collections.Map or kotlin.collections.MutableMap instead.

因此,如果我们查看 get 的代码函数 kotlin.collections.Map定义,we can see that it returns a nullable value type

    /**
* Returns the value corresponding to the given [key], or `null` if such a key is not present in the map.
*/
public operator fun get(key: K): V?

因此 Kotlin 编译器可以查看 HashMap.get(...)并推断出这一点,因为它正在实现 kotlin.collections.Map.get(...) ,返回值必须是一个可以为空的值,在我们的例子中是String? .

解决方法:外部注释

无论出于何种原因,Jackson 都没有使用可以解决此问题的可空性注释。幸运的是,IntelliJ 提供了一种解决方法,虽然不那么严格,但会提供有用的警告:external annotations .

一旦我按照说明操作...

  1. Alt+Enter → '注释方法...'

    enter image description here

  2. 选择 'Nullable' 注释

    enter image description here

  3. 保存 annotations.xml

现在node.get("")将显示警告。

enter image description here

此注释对 Kotlin 编译器不可见,因此它只能是警告 - 而不是编译错误。

关于kotlin - 从 Kotlin 调用 Java 时的可空规则是什么,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72480608/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com