Kotlin/Java互操作性中,Integer! 不会自动转换成Int?
我有以下代码:
fun extractWorkspaceId (token : String) : Int? = extractClaim(token) { it.get("ws", Integer::class.java) }
extractClaim 被定义为类型 fun <T> extractClaim (token : String, resolver : (Claims) -> T) : T,其中 Claims 是一个包含方法 T <T> get(String, Class<T>) 的Java类。编译时我得到如下错误:
JwtTokenService.kt:31:76 Return type mismatch: expected 'Int?', actual 'Integer!'.
显然 Integer 应该会自动转换为 Int,那么在这种情况下,为什么 Integer! 没有自动转换为 Int??在表达式末尾添加 as Int? 可以正常工作,但为什么不会自动发生?
解决方案
从来就没有 java.lang.Integer 与 kotlin.Int 之间的隐式转换。这是设计上的要求:数字类型必须彼此显式地进行转换,而不能隐式进行。
数值类型并非互为子类型。Kotlin要求显式转换,以避免悄无声息的数据丢失和意外行为。
fun f(javaInteger: Integer) {
val kotlinInt: Int = javaInteger // does not compile!
}
你可能在想的行为是,涉及 Integer 的Java声明被导入到Kotlin中,作为 Int!(或 Int?)。这确实是对的,但在你的情况,Java声明并不涉及任何 Integer:
// this is a totally generic method! No Integer involved at all!
<T> T get(String s, Class<T> c)
get 只是在导入到Kotlin时几乎没有变动:
// from Kotlin's perspective:
fun <T> get(s: String!, c: Class<T!>!): T!
类型 Integer 只有在你调用 get 时才会出现,而 get 位于Kotlin代码中,因此就适用Kotlin的规则。
除了 as Int?,你还可以
- 在末尾调用
.toInt()将Integer转换为Int,或 - 传入
Int::class.javaObjectType代替Integer::class.java。这在Java中的效果与Integer.class相同,但在Kotlin中的类型是Class<Int>。
旁注:这种情况与例如 java.util.ArrayList 和 kotlin.collections.ArrayList 不同。Kotlin的 ArrayList 只是Java的 ArrayList 的一个类型别名,因此可以在它们之间隐式“转换”。
fun f(javaList: java.util.ArrayList<String>) {
// OK!
val kotlinList: kotlin.collections.ArrayList<String> = javaList
}
其实并没有进行任何“转换”——它们只是同一类型的两种不同名称。
java.lang.Integer 和 kotlin.Int 则是不同的类型。