我正在尝试探索scala case类的内部结构。为此,我正在创建简单的案例类并分析scala编译器使用javap
创建的字节码。
我很惊讶地发现,当我创建一个只有一个String字段的case类时:
case class MyCaseClass(value: String)
伴随对象MyCaseClass$
的字节码包含两个apply
方法:
public MyCaseClass apply(java.lang.String);
Code:
0: new #23 // class MyCaseClass
3: dup
4: aload_1
5: invokespecial #26 // Method MyCaseClass."<init>":(Ljava/lang/String;)V
8: areturn
public java.lang.Object apply(java.lang.Object);
Code:
0: aload_0
1: aload_1
2: checkcast #53 // class java/lang/String
5: invokevirtual #55 // Method apply:(Ljava/lang/String;)LMyCaseClass;
8: areturn
(使用scalac 2.11.6编译)
第一个是我期望的-将String作为参数,并创建我的case类的新实例,并将此参数传递给构造函数。第二个对象获取一个对象,将其强制转换为String,然后调用第一个对象。
我想不出第二种方法的任何用途。为什么需要它?此行为记录在任何地方吗?
答案 0 :(得分:3)
默认的伴随对象扩展了函数类型,在这种情况下为Function1[String, MyCaseClass]
(在Scala中通常写为String => MyCaseClass
)。
Function1#apply
的JVM签名为Object apply(Object)
,因此覆盖方法必须具有相同的签名。