我了解Kotlin是一种静态类型的语言,并且所有类型都是在编译时定义的。
这里是一个when
表达式,它返回不同的类型:
fun main(){
val x = readLine()?.toInt() ?: 0
val y = when(x){
1 -> 42
2 -> "Hello"
else -> 3.14F
}
println(y::class.java)
}
在运行时(JVM 1.8上的Kotlin 1.3.41),这是输出:
当x
= 1时,它将打印class java.lang.Integer
当x
= 2时,它将打印class java.lang.String
否则,它将打印class java.lang.Float
编译器何时确定y
的类型?或者,在编译期间,编译器如何推断y
的类型?
答案 0 :(得分:2)
实际上,在这种情况下,when表达式的类型解析为INSTR
,因此Any
变量可以具有任何值。 IDE甚至会警告您y
,至少是Android Studio,还有Kotlin Playground。
答案 1 :(得分:2)
该变量的类型为Any
(作为所有这些类型中最小的超类),但基本值未受影响。
是什么意思?您只能安全地访问所有所有类型共有的属性(因此,仅Any
类型可用的属性。::class.java
属性适用于所有类型。
请参阅此示例-我使用其他一些类型来很好地了解其含义。
abstract class FooGoo {
fun foogoo(): String = "foo goo"
}
class Foo: FooGoo() {
fun foo(): String = "foo foo"
}
class Goo: FooGoo() {
fun goo(): String = "goo goo"
}
class Moo {
fun moo(): String = "moo moo"
}
fun main(x: Int) {
val n = when (x) {
0 -> Foo()
1 -> Goo()
else -> throw IllegalStateException()
} // n is implicitly cast to FooGoo, as it's the closes superclass of both, Foo and Goo
// n now has only methods available for FooGoo, so, only `foogoo` can be called (and all methods for any)
val m = when (x) {
0 -> Foo()
1 -> Goo()
else -> Moo()
} // m is implicitly cast to Any, as there is no common supertype except Any
// m now has only methods available for Any() - but properties for that class are not changed
// so, `m::class.java` will return real type of that method.
println(m::class.java) // // Real type of m is not erased, we still can access it
if (m is FooGoo) {
m.foogoo() // After explicit cast we are able to use methods for that type.
}
}
答案 2 :(得分:0)
在编译期间,y
的推断类型为Any
,它是Kotlin中所有类型的超类型。在运行时,y
可以[字面意义上]引用任何类型的对象。 IDE生成警告"Conditional branch result of type Int/String/Float is implicitly cast to Any"
。
在示例中,
当x
= 1时,它指向类型为java.lang.Integer
的对象。
当x
= 2时,它指向类型为java.lang.String
的对象。
否则,它引用类型为java.lang.Float
的对象。
感谢Slaw的简要说明:
变量的声明类型与它引用的对象的实际类型之间是有区别的。和做
val x: Any = "Hello, Wold!"
没什么不同;