Есть ли время или пространство накладные для классов классов над обычными классами в Scala?

Есть ли какие-либо накладные расходы при использовании классов case в Scala по сравнению с обычными классами? Использует ли он какую-либо дополнительную память, делает больше в строительстве или делает больше в полевом доступе? Или это буквально просто бесплатный equals/hashcode/tostring/apply/unapply/etc для классов внизу иерархии типов?

Мой пример использования - это класс, который заслуживает того, чтобы быть классом case (неизменяемым и равным, если все поля равны), но я в домене, где производительность критическая.

(Пожалуйста, не отвечайте по строкам "перестаньте беспокоиться о преждевременной оптимизации".)

Ответ 1

Классы классов всегда сохраняют все свои параметры как поля. Другие классы выполняются только в том случае, если их параметры ссылаются каким-либо методом. Это единственная разница в производительности, о которой я могу думать, за исключением большего размера кода из-за дополнительных методов.

Ответ 2

Если вы скомпилируете минимальный пример:

class Ordinary(val i: Int) { }

case class Case(i: Int) { }

вы обнаружите, что байт-код для обычного класса меньше (~ 700 против ~ 3500); вы также можете найти с javap -c -private -v <Classname>, что конструктор имеет дополнительный вызов метода для инициализатора свойств продукта (который фактически ничего не делает, поэтому его следует оптимизировать компилятором JIT).

Поэтому для повторного использования одного класса это не должно иметь большого значения. Если у вас много тысяч таких классов, вы можете столкнуться с проблемой повышенного байт-кода.

Ответ 3

Сначала очевидный: байт-код больше из-за созданных дополнительных методов.

Классы классов сохраняют параметры первого списка параметров как val членов. Если вам не нужен доступ к параметру, отличному от конструкции объекта, это расточительно.

Так как Scala 2.8, классы case также сохраняют параметры из последующих разделов параметров для поддержки метода 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);
}