[英]Understanding Type in Compiled Scala File
鉴于:
$cat build.sbt
scalaVersion := "2.12.1"
$cat src/main/scala/net/X.scala
package net
trait Foo
object X {
val a: Int with Foo = 42.asInstanceOf[Int with Foo]
println(a + a)
}
通过sbt compile
,我将输出class
文件javap :
$javap target/scala-2.12/classes/net/X\$.class
Compiled from "X.scala"
public final class net.X$ {
public static net.X$ MODULE$;
public static {};
public int a();
}
$javap target/scala-2.12/classes/net/X.class
Compiled from "X.scala"
public final class net.X {
public static int a();
}
为什么a
有类型int
?
我在object X
Int with Foo
指定了一种Int with Foo
类型。
这只是Scala中所有交集类型被编译为JVM字节码的方式。 JVM无法Int with Foo
表示Int with Foo
,因此编译器会将类型擦除为第一个“简单”类型:在这种情况下为Int
。 这意味着,如果您使用像Foo
这样的值a
则编译器必须在字节码中插入强制类型转换。
看一下以下REPL会话:
Welcome to Scala 2.12.1 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_111).
Type in expressions for evaluation. Or try :help.
scala> trait Foo { def foo = "foo" }
defined trait Foo
scala> trait Bar { def bar = "bar" }
defined trait Bar
scala> class FooBar extends Foo with Bar
defined class FooBar
scala> class Test { val foobar: Foo with Bar = new FooBar }
defined class Test
scala> object Main {
| def main(): Unit = {
| val test = new Test().foobar
| println(test.foo)
| println(test.bar)
| }
| }
defined object Main
scala> :javap -p -filter Test
Compiled from "<console>"
public class Test {
private final Foo foobar;
public Foo foobar();
public Test();
}
scala> :javap -c -p -filter Main
Compiled from "<console>"
...
public void main();
Code:
...
15: invokeinterface #62, 1 // InterfaceMethod Foo.foo:()Ljava/lang/String;
...
27: checkcast #23 // class Bar
30: invokeinterface #69, 1 // InterfaceMethod Bar.bar:()Ljava/lang/String;
...
Int with Foo
实际上是一个特例。 Int
是最终类型, Foo
是特征。 显然,编译器更喜欢最终类型和类而不是特征。 因此,在Foo with Bar
Foo
和Foo
中, Foo
是一个特征,而Bar
是一个类,该类型仍然被擦除为Bar
而不是Foo
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.