SuperClass 可以是其子类的一种类型吗?

SuperClass can be a type of its SubClasses?

提问人:Mohammad 提问时间:6/9/2023 更新时间:6/9/2023 访问量:77

问:

在下面的代码中,n1 变量的确切类型是什么?

fun main() {
    var n1: Number = 758.3
    var n2: Double = n1
    
    if (n1 is Double) {
        println("Double")
    } else if (n1 is Number) {
        println("Number")
    } else {
        println("else")
    }
}

如果是 Double,为什么第 3 行(n2 变量)有编译时错误?

如果是数字,为什么删除第 3 行(删除 n2 变量)时会打印?我们预计会打印出来DoubleNumber

我们知道 n1 是 Number,它不是 Double,除非它转换为 Double。我们没有这样做!

Kotlin 继承 转换

评论

1赞 Jorn 6/9/2023
Kotlin 编译器很智能。它知道第 6 行是 Double,因为您已经完成了检查。它还不知道在第 3 行。此功能称为“智能投射”。因此,如果您将第 3 行移动到第一行,它将编译得很好。n1isif

答:

3赞 Ivo 6/9/2023 #1

n1既是 a 又是 a。如果你写NumberDouble

var n1: Number = 758.3

if (n1 is Double) {
    println("Double")
}
if (n1 is Number) {
    println("Number")
}

你会看到两者都被打印出来。此检查在运行时完成。这不能在编译时完成,这就是第 3 行给出错误的原因。请注意,可以写

if (n1 is Double) {
    var n2: Double = n1
    println("Double")
}

因为编译器知道,当它进入内部时,它必须是双精度的,并且可以进行这种同化if

3赞 Joffrey 6/9/2023 #2

n1 变量的确切类型是什么?

变量的类型是 ,因为您这样声明它。因此,编译器将禁止任何假设超过此值的内容。例如,它禁止将此变量的值分配给类似 的变量,因为它不允许你为包含的值假定更精确的类型(从编译器的角度来看,该值理论上可以是 的任何子类型)。n1NumberDoublen2n1Number

如果是数字,为什么删除第 3 行(删除 n2 变量)时会打印 Double?我们预计该数字将被打印出来

您必须将变量的类型与其的运行时类型区分开来。在这里,存储在变量中的在运行时属于类型。由于这是 的子类型,因此该值也是 的类型(这就是为什么编译器允许将其存储在 type 的变量中的原因)。n1DoubleNumberNumbern1Number

执行检查时,这些检查是检查类型而不是变量类型的运行时检查。这就是为什么在运行时 both 和 都是 true 的原因,因为指向的值是这两种类型。isn1 is Numbern1 is Doublen1

评论

0赞 Mohammad 6/10/2023
变量值的运行时类型是否与变量值的向下转换类型或实数类型相同?- 在我的代码中,n1 的变量类型是 Number,但存储在 n1 中的 n1 的值类型是 Double。所以加倍上调到数字。n1 值的运行时类型为 Double。我们可以在没有任何强制转换的情况下得出结论变量值的运行时类型是它的真实类型吗?
1赞 Joffrey 6/10/2023
强制转换只是编译器转换值的编译时构造,在运行时只有值本身的实际类型
0赞 Joffrey 6/11/2023
实际上,我写的并不完全正确,强制转换不仅存在于编译时。还会检查大多数向下转换,这意味着它们还会在运行时检查实际值是否与强制转换为的任何类型匹配。但是,如前所述,它们确实处理了值的实际运行时类型。