在Scala / Java中(〜在JVM上),有一些较小的情况,行为不同,如:
/* "Dynamic" cast */
"".getClass.cast("Foo")
//res0: Any = Foo
/* "Static" cast */
classOf[String].cast("Foo")
//res1: String = Foo
/* "Compile time cast" */
"Foo".asInstanceOf[String]
res2: String = Foo
编译时间和运行时间之间的差距更大,是否有语言设计POV的原因为什么这可能是一件“好事”?
走向另一个方向:是否有(静态类型)语言没有编译时和运行时类型之间的任何差异?
答案 0 :(得分:6)
第一个结果的原因是getClass
方法在Java中具有以下签名
public final Class<?> getClass()
Scala继承的。虽然我们知道如果我们在类型T的引用上调用getClass
,签名可能是
public final Class<? extends T> getClass()
编译器没有。您可以想象一些语言扩展,以提供一种特殊类型,表示将启用
的接收器的静态类型public final Class<? extends Receiver> getClass()
或getClass
编译器中的某种特殊大小写。事实上,Snoracle Java确实是特殊情况getClass
,但我不确定Java语言规范是否需要它。但是,如果您有一些特定静态类型T的引用,则没有理由不能执行等效的T.class
(java)或classOf[T]
(scala)。换句话说,这样的扩展不会带来更大的表达能力,但会使语言的实现复杂化。
至于“编译时间演员”与“静态'演员阵容”,那里真的没什么区别。编译器将x.asInstanceOf[T]
转移到classOf[T].cast(x)
是正确的。
任何具有子类型的语言都可能会使静态已知类型的引用不如它所引用的值的类型具体。具有静态类型系统但没有子类型的语言通常没有运行时类型的概念,因为只有一个实际类型存在于给定类型名称中。在这些语言中,类型在运行时被擦除,就像在JVM上擦除类型参数一样。
我希望这与运行时类型的值相比,有助于理解静态类型的引用。
答案 1 :(得分:1)
C没有运行时类型信息(RTTI)。所以静态类型是运行时类型。更准确地说,这使编译器能够从对象文件中完全消除类型信息,并生成更快的代码(在程序执行期间不需要检查)。对于链接,信息位于标题中。
在C ++中,RTTI仅存在虚拟继承/抽象基类,由于性能不佳(C ++标准),这是一种令人沮丧的习惯用法。
在Java中(据我所知),首选的习惯用法(至少7年前)是使用非常通用的界面。这意味着没有太多的编译时类型信息。当然,Java中的泛型将所有Object都作为静态类型。所以所有信息都是运行时(带有相应的开销)。这背后的原因似乎是静态类型系统要么过于严格(C,Pascal)而需要漏洞(void *)或相对复杂(C ++,Haskell)。
在Haskell中,编译类型通常是运行时类型,除了高阶类型和存在类型的情况。 GHC由于某种原因(反射?类型类实例化?)虽然不使用它来提高效率。所以类型信息都是runtme。