为 Scala 代码生成的字节码的奇怪行为
Strange behavour of bytecode generated for Scala code
我正在玩 Scala 特性。
trait Animal{
def speak = println("speaking..")
def comeToMaster: Unit
}
class Cat extends Animal{
override def speak: Unit = println("meow....")
def comeToMaster = println("catch me if you can..")
}
object Sample extends App{
val kity = new Cat
kity.speak
kity.comeToMaster
}
但是当我看到 Scala 编译器生成的字节码时,
javap -c Animal.class
Compiled from "Sample.scala"
public abstract class Animal$class {
public static void speak(Animal);
Code:
0: getstatic #13 // Field scala/Predef$.MODULE$:Lscala/Predef$;
3: ldc #15 // String speaking..
5: invokevirtual #19 // Method scala/Predef$.println:(Ljava/lang/Object;)V
8: return
public static void $init$(Animal);
Code:
0: return
}
注意字节码中只有speak方法。 comeToMaster 方法在哪里?我在删除所有 class 个文件后再次尝试。尽管如此,它还是给了我相同的结果。所以,我没有得到 Scala 编译器生成的 Java 字节码的这种奇怪行为。
但是当我看到Cat class的字节码时,两种方法都有。
javap -c Cat.class
Compiled from "Sample.scala"
public class Cat implements Animal {
public void speak();
Code:
0: getstatic #18 // Field scala/Predef$.MODULE$:Lscala/Predef$;
3: ldc #20 // String meow....
5: invokevirtual #24 // Method scala/Predef$.println:(Ljava/lang/Object;)V
8: return
public void comeToMaster();
Code:
0: getstatic #18 // Field scala/Predef$.MODULE$:Lscala/Predef$;
3: ldc #29 // String catch me if you can..
5: invokevirtual #24 // Method scala/Predef$.println:(Ljava/lang/Object;)V
8: return
public Cat();
Code:
0: aload_0
1: invokespecial #32 // Method java/lang/Object."<init>":()V
4: aload_0
5: invokestatic #38 // Method Animal$class.$init$:(LAnimal;)V
8: return
}
这应该取决于版本。我的输出是
$ javap -c Cat.class
Compiled from "Animal.scala"
public class Cat implements Animal {
public void speak();
Code:
0: getstatic #18 // Field scala/Predef$.MODULE$:Lscala/Predef$;
3: ldc #20 // String meow....
5: invokevirtual #24 // Method scala/Predef$.println:(Ljava/lang/Object;)V
8: return
public void comeToMaster();
Code:
0: getstatic #18 // Field scala/Predef$.MODULE$:Lscala/Predef$;
3: ldc #29 // String catch me if you can..
5: invokevirtual #24 // Method scala/Predef$.println:(Ljava/lang/Object;)V
8: return
public Cat();
Code:
0: aload_0
1: invokespecial #32 // Method java/lang/Object."<init>":()V
4: aload_0
5: invokestatic #36 // InterfaceMethod Animal.$init$:(LAnimal;)V
8: return
}
$ javap -c Animal.class
Compiled from "Animal.scala"
public interface Animal {
public static void speak$(Animal);
Code:
0: aload_0
1: invokespecial #15 // InterfaceMethod speak:()V
4: return
public void speak();
Code:
0: getstatic #22 // Field scala/Predef$.MODULE$:Lscala/Predef$;
3: ldc #24 // String speaking..
5: invokevirtual #28 // Method scala/Predef$.println:(Ljava/lang/Object;)V
8: return
public abstract void comeToMaster();
public static void $init$(Animal);
Code:
0: return
}
Scala 2.12.4 (jdk 1.8.0_162)
尝试使用 classes 查看您的目录。
可能除了抽象 class Animal$class
你还有接口 Animal
.
将 Animal.scala
放在一个目录中,将 Animal$class.scala
放在另一个目录中,然后到处调用 javap。使用 Scala 2.11.12 输出是
$ javap -c Animal.class
Compiled from "Animal.scala"
public interface Animal {
public abstract void speak();
public abstract void comeToMaster();
}
$ javap -c Animal$class.class
Compiled from "Animal.scala"
public abstract class Animal$class {
public static void speak(Animal);
Code:
0: getstatic #13 // Field scala/Predef$.MODULE$:Lscala/Predef$;
3: ldc #15 // String speaking..
5: invokevirtual #19 // Method scala/Predef$.println:(Ljava/lang/Object;)V
8: return
public static void $init$(Animal);
Code:
0: return
}
我正在玩 Scala 特性。
trait Animal{
def speak = println("speaking..")
def comeToMaster: Unit
}
class Cat extends Animal{
override def speak: Unit = println("meow....")
def comeToMaster = println("catch me if you can..")
}
object Sample extends App{
val kity = new Cat
kity.speak
kity.comeToMaster
}
但是当我看到 Scala 编译器生成的字节码时,
javap -c Animal.class
Compiled from "Sample.scala"
public abstract class Animal$class {
public static void speak(Animal);
Code:
0: getstatic #13 // Field scala/Predef$.MODULE$:Lscala/Predef$;
3: ldc #15 // String speaking..
5: invokevirtual #19 // Method scala/Predef$.println:(Ljava/lang/Object;)V
8: return
public static void $init$(Animal);
Code:
0: return
}
注意字节码中只有speak方法。 comeToMaster 方法在哪里?我在删除所有 class 个文件后再次尝试。尽管如此,它还是给了我相同的结果。所以,我没有得到 Scala 编译器生成的 Java 字节码的这种奇怪行为。
但是当我看到Cat class的字节码时,两种方法都有。
javap -c Cat.class
Compiled from "Sample.scala"
public class Cat implements Animal {
public void speak();
Code:
0: getstatic #18 // Field scala/Predef$.MODULE$:Lscala/Predef$;
3: ldc #20 // String meow....
5: invokevirtual #24 // Method scala/Predef$.println:(Ljava/lang/Object;)V
8: return
public void comeToMaster();
Code:
0: getstatic #18 // Field scala/Predef$.MODULE$:Lscala/Predef$;
3: ldc #29 // String catch me if you can..
5: invokevirtual #24 // Method scala/Predef$.println:(Ljava/lang/Object;)V
8: return
public Cat();
Code:
0: aload_0
1: invokespecial #32 // Method java/lang/Object."<init>":()V
4: aload_0
5: invokestatic #38 // Method Animal$class.$init$:(LAnimal;)V
8: return
}
这应该取决于版本。我的输出是
$ javap -c Cat.class
Compiled from "Animal.scala"
public class Cat implements Animal {
public void speak();
Code:
0: getstatic #18 // Field scala/Predef$.MODULE$:Lscala/Predef$;
3: ldc #20 // String meow....
5: invokevirtual #24 // Method scala/Predef$.println:(Ljava/lang/Object;)V
8: return
public void comeToMaster();
Code:
0: getstatic #18 // Field scala/Predef$.MODULE$:Lscala/Predef$;
3: ldc #29 // String catch me if you can..
5: invokevirtual #24 // Method scala/Predef$.println:(Ljava/lang/Object;)V
8: return
public Cat();
Code:
0: aload_0
1: invokespecial #32 // Method java/lang/Object."<init>":()V
4: aload_0
5: invokestatic #36 // InterfaceMethod Animal.$init$:(LAnimal;)V
8: return
}
$ javap -c Animal.class
Compiled from "Animal.scala"
public interface Animal {
public static void speak$(Animal);
Code:
0: aload_0
1: invokespecial #15 // InterfaceMethod speak:()V
4: return
public void speak();
Code:
0: getstatic #22 // Field scala/Predef$.MODULE$:Lscala/Predef$;
3: ldc #24 // String speaking..
5: invokevirtual #28 // Method scala/Predef$.println:(Ljava/lang/Object;)V
8: return
public abstract void comeToMaster();
public static void $init$(Animal);
Code:
0: return
}
Scala 2.12.4 (jdk 1.8.0_162)
尝试使用 classes 查看您的目录。
可能除了抽象 class Animal$class
你还有接口 Animal
.
将 Animal.scala
放在一个目录中,将 Animal$class.scala
放在另一个目录中,然后到处调用 javap。使用 Scala 2.11.12 输出是
$ javap -c Animal.class
Compiled from "Animal.scala"
public interface Animal {
public abstract void speak();
public abstract void comeToMaster();
}
$ javap -c Animal$class.class
Compiled from "Animal.scala"
public abstract class Animal$class {
public static void speak(Animal);
Code:
0: getstatic #13 // Field scala/Predef$.MODULE$:Lscala/Predef$;
3: ldc #15 // String speaking..
5: invokevirtual #19 // Method scala/Predef$.println:(Ljava/lang/Object;)V
8: return
public static void $init$(Animal);
Code:
0: return
}