在Scala中使用case类与普通类相比,是否有任何开销?它是否使用任何额外的内存,在构造中做更多,或在现场访问中做更多?或者,对于类型层次结构底部的类,它是否只是自由等于/ hashcode / tostring / apply / unapply / etc?
我的用例是一个值得成为案例类的类(如果所有字段都相等则不可变且相等),但我处于性能至关重要的域中。
(请不要回答“不要过早担心过早优化”。)
答案 0 :(得分:17)
案例类始终将所有参数保留为字段。其他类只有在某些方法引用其参数时才会执行。这是我能想到的唯一性能差异,除了由于额外的方法而导致的更大的代码大小。
答案 1 :(得分:7)
如果你编译一个最小的例子:
class Ordinary(val i: Int) { }
case class Case(i: Int) { }
你发现普通类的字节码较小(~700 vs.~3500);您还可以找到javap -c -private -v <Classname>
构造函数对Product trait初始化程序的额外方法调用(实际上并没有执行任何操作,因此应该由JIT编译器进行优化)。
因此,对于重复使用一个类,它应该没有太大的区别。如果你有数千个这样的类,你可能会发现字节码增加有问题。
答案 2 :(得分:5)
首先显而易见的一点是:由于创建了额外的方法,字节码更大。
案例类将第一个参数列表的参数保留为val
个成员。如果您不需要访问除构造对象之外的参数,这将是浪费。
自Scala 2.8起,案例类还保留后续参数部分中的参数以支持copy
方法。这是一个实现细节,是subject to change。
scala> case class A(a: Int)(b: Int)
defined class A
scala> val a = A(0)(1)
a: A = A(0)
scala> a.copy()()
res9: A = A(0)
scala> :javap -private A
Compiled from "<console>"
public class A extends java.lang.Object implements scala.ScalaObject,scala.Product,scala.Serializable{
private final int a;
private final int b;
public scala.collection.Iterator productIterator();
public scala.collection.Iterator productElements();
public int a();
public A copy(int, int);
public int copy$default$2(int);
public int copy$default$1();
public int hashCode();
public java.lang.String toString();
public boolean equals(java.lang.Object);
public java.lang.String productPrefix();
public int productArity();
public java.lang.Object productElement(int);
public boolean canEqual(java.lang.Object);
private final boolean gd1$1(int);
public A(int, int);
}