我不知道在哪里描述或记录了用于合并自动和显式伴随对象的算法(编译器源除外),但是通过编译代码然后检查生成的伴随对象(使用 javap),我们可以看到有什么区别是(这是 scala 2.10.4)。
这是为案例类生成的伴随对象(没有额外的伴随对象):
Compiled from "zip.sc"
public final class A$ extends scala.runtime.AbstractFunction2<Object, Object, A> implements scala.Serializable {
public static final A$ MODULE$;
public static {};
public A apply(int, int);
public scala.Option<scala.Tuple2<java.lang.Object, java.lang.Object>> unapply(A);
public java.lang.Object apply(java.lang.Object, java.lang.Object);
public final java.lang.String toString();
}
添加伴生对象后,生成的内容如下:
Compiled from "zip.sc"
public final class A$ implements scala.Serializable {
public static final A$ MODULE$;
public static {};
public A apply(int, int);
public scala.Option<scala.Tuple2<java.lang.Object, java.lang.Object>> unapply(A);
public int A2Int(A);
}
由显式伴随对象定义引起的生成伴随对象的差异似乎是:
- 它不再扩展 AbstractFunction2
- 它不再具有与项目符号 1 相关的工厂方法(应用)
- 它不再覆盖 toString 方法(如果需要,我想您应该提供一个)
- 您的 A2Int 方法已添加
如果将案例类更改为普通类(以及使其编译所需的最小更改),结果如下:
Compiled from "zip.sc"
public final class A$ {
public static final A$ MODULE$;
public static {};
public A apply(int, int);
public int A2Int(A);
}
所以看起来如果你声明自己的伴生对象,至少在这个简单的例子中,效果是你的新方法被添加到伴生对象中,并且它的一些实现和功能也丢失了。如果我们试图覆盖一些剩余的自动生成的东西,看看会发生什么会很有趣,但是剩下的东西不多了,所以一般来说不太可能引起冲突。
案例类的一些好处与生成的代码无关,例如无需显式添加“val”关键字即可公开类变量。这是上面所有 3 个反编译示例的修改后的源代码。
版本 1(没有明确的伴随对象):
case class A(i1:Int,i2:Int)
版本 2 是您的原始版本。
版本 3(无案例类):
object A {
implicit def A2Int(a:A)=a.i1
def apply(a:Int,b:Int):A = new A(a,b)
}
class A(val i1:Int,val i2:Int)
object Run extends App{
import A._
val a=A(1,2)
val i:Int=a
}
在版本 3 中,我们需要将 val 添加到 A 类参数(否则它们是私有的),我们必须将工厂方法添加到我们的伴随对象,或者在创建 A(1 ,2)。