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

pho*_*nix 10 scala

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

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

(请不要回答"不要过早担心过早优化".)

Mar*_*sky 17

案例类始终将所有参数保留为字段.其他类只有在某些方法引用其参数时才会执行.这是我能想到的唯一性能差异,除了由于额外的方法而导致的更大的代码大小.


Rex*_*err 7

如果编译一个最小的例子:

class Ordinary(val i: Int) { }

case class Case(i: Int) { }
Run Code Online (Sandbox Code Playgroud)

你会发现普通类的字节码较小(~700 vs.~3500); 你也发现javap -c -private -v <Classname>构造函数有一个额外的方法调用Product trait初始化器(它实际上没有做任何事情,因此应该由JIT编译器进行优化).

因此,对于重复使用一个类,它应该没有太大的区别.如果您有数千个这样的类,您可能会发现字节码增加有问题.


ret*_*nym 5

首先是显而易见的:由于创建了额外的方法,字节码更大.

案例类将第一个参数列表的参数保留为val成员.如果您不需要访问除构造对象之外的参数,这将是浪费.

从Scala 2.8开始,案例类还保留后续参数部分中的参数以支持该copy方法.这是一个实现细节,可能会有所变化.

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);
}
Run Code Online (Sandbox Code Playgroud)