在Scala中常规类的案例类是否有任何时间或空间开销?

时间:2011-10-04 21:09:12

标签: scala

在Scala中使用case类与普通类相比,是否有任何开销?它是否使用任何额外的内存,在构造中做更多,或在现场访问中做更多?或者,对于类型层次结构底部的类,它是否只是自由等于/ hashcode / tostring / apply / unapply / etc?

我的用例是一个值得成为案例类的类(如果所有字段都相等则不可变且相等),但我处于性能至关重要的域中。

(请不要回答“不要过早担心过早优化”。)

3 个答案:

答案 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);
}