我有一个对象:
object A {
val init = println("Hello")
}
Run Code Online (Sandbox Code Playgroud)
我在一个特征中使用它:
trait SomeTratit {
val a = A.init
}
Run Code Online (Sandbox Code Playgroud)
然后我在课堂上使用trait:
class SomeClass extends SomeTrait
Run Code Online (Sandbox Code Playgroud)
当我实例化SomeClass时,new SomeClass我希望"Hello"在控制台中看到,但是没有得到它.为什么?
此外,我希望在实例化多个对象时只看到一次"Hello",但在控制台中看不到任何"Hello"
我不知道这是否应该被视为一个错误,但这是如何发生的。
如果你查看生成的字节码object A,它是这样的:
public final class A$ {
public static final A$ MODULE$;
private final scala.runtime.BoxedUnit init;
public static {};
Code:
0: new #2 // class A$
3: invokespecial #12 // Method "<init>":()V
6: return
public void init();
Code:
0: return
private A$();
Code:
0: aload_0
1: invokespecial #16 // Method java/lang/Object."<init>":()V
4: aload_0
5: putstatic #18 // Field MODULE$:LA$;
8: aload_0
9: getstatic #23 // Field scala/Predef$.MODULE$:Lscala/Predef$;
12: ldc #25 // String Hello
14: invokevirtual #29 // Method scala/Predef$.println:(Ljava/lang/Object;)V
17: getstatic #34 // Field scala/runtime/BoxedUnit.UNIT:Lscala/runtime/BoxedUnit;
20: putfield #36 // Field init:Lscala/runtime/BoxedUnit;
23: return
}
Run Code Online (Sandbox Code Playgroud)
您可以println("Hello")在 的构造函数中找到您所期望的A$,但在init(). 这是完全正确的,因为您的意图println("Hello")是每次调用时都不会执行init(),对吗?
然而,问题来了SomeClass:
public class SomeClass implements SomeTrait {
public void a();
Code:
0: return
public void SomeTrait$_setter_$a_$eq(scala.runtime.BoxedUnit);
Code:
0: return
public SomeClass();
Code:
0: aload_0
1: invokespecial #21 // Method java/lang/Object."<init>":()V
4: aload_0
5: invokestatic #27 // Method SomeTrait$class.$init$:(LSomeTrait;)V
8: return
}
Run Code Online (Sandbox Code Playgroud)
什么?!里面也什么都没有SomeClass.a()!但想想看,这也是完全合理的:我为什么要费心调用它,因为实际上什么都没有A$.init(),它也不返回任何内容(即没有要设置的字段)?为什么不直接优化它(也许 Java 做了这个优化。或者 Scala 做了。我不知道)?但是,这种优化也消除了 的唯一外观A$,这意味着不会调用 构造函数A$。这就是为什么Hello从来没有出现过。
但是,如果您稍微更改代码,使 的字节码init()不会为空,如下所示:
object A {
val init = { println("Hello"); 1 }
}
Run Code Online (Sandbox Code Playgroud)
编译为以下字节码:
public int init();
Code:
0: aload_0
1: getfield #17 // Field init:I
4: ireturn
Run Code Online (Sandbox Code Playgroud)
在这种情况下,你会找到这样的字节码SomeClass.a():
public int a();
Code:
0: aload_0
1: getfield #15 // Field a:I
4: ireturn
Run Code Online (Sandbox Code Playgroud)
该字段的设置位置SomeTrait$class:
public abstract class SomeTrait$class {
public static void $init$(SomeTrait);
Code:
0: aload_0
1: getstatic #13 // Field A$.MODULE$:LA$;
4: invokevirtual #17 // Method A$.init:()I
7: invokeinterface #23, 2 // InterfaceMethod SomeTrait.SomeTrait$_setter_$a_$eq:(I)V
12: return
}
Run Code Online (Sandbox Code Playgroud)
A$.init()被调用来设置这个字段,所以在这种情况下你可以期待Hello出现。
| 归档时间: |
|
| 查看次数: |
9505 次 |
| 最近记录: |