Để có sự hiểu biết cuối cùng về một lớp trường hợp là gì:
hãy giả sử định nghĩa lớp trường hợp sau:
case class Foo(foo:String, bar: Int)
và sau đó làm như sau trong thiết bị đầu cuối:
$ scalac -print src/main/scala/Foo.scala
Scala 2.12.8 sẽ xuất ra:
...
case class Foo extends Object with Product with Serializable {
<caseaccessor> <paramaccessor> private[this] val foo: String = _;
<stable> <caseaccessor> <accessor> <paramaccessor> def foo(): String = Foo.this.foo;
<caseaccessor> <paramaccessor> private[this] val bar: Int = _;
<stable> <caseaccessor> <accessor> <paramaccessor> def bar(): Int = Foo.this.bar;
<synthetic> def copy(foo: String, bar: Int): Foo = new Foo(foo, bar);
<synthetic> def copy$default$1(): String = Foo.this.foo();
<synthetic> def copy$default$2(): Int = Foo.this.bar();
override <synthetic> def productPrefix(): String = "Foo";
<synthetic> def productArity(): Int = 2;
<synthetic> def productElement(x$1: Int): Object = {
case <synthetic> val x1: Int = x$1;
(x1: Int) match {
case 0 => Foo.this.foo()
case 1 => scala.Int.box(Foo.this.bar())
case _ => throw new IndexOutOfBoundsException(scala.Int.box(x$1).toString())
}
};
override <synthetic> def productIterator(): Iterator = scala.runtime.ScalaRunTime.typedProductIterator(Foo.this);
<synthetic> def canEqual(x$1: Object): Boolean = x$1.$isInstanceOf[Foo]();
override <synthetic> def hashCode(): Int = {
<synthetic> var acc: Int = -889275714;
acc = scala.runtime.Statics.mix(acc, scala.runtime.Statics.anyHash(Foo.this.foo()));
acc = scala.runtime.Statics.mix(acc, Foo.this.bar());
scala.runtime.Statics.finalizeHash(acc, 2)
};
override <synthetic> def toString(): String = scala.runtime.ScalaRunTime._toString(Foo.this);
override <synthetic> def equals(x$1: Object): Boolean = Foo.this.eq(x$1).||({
case <synthetic> val x1: Object = x$1;
case5(){
if (x1.$isInstanceOf[Foo]())
matchEnd4(true)
else
case6()
};
case6(){
matchEnd4(false)
};
matchEnd4(x: Boolean){
x
}
}.&&({
<synthetic> val Foo$1: Foo = x$1.$asInstanceOf[Foo]();
Foo.this.foo().==(Foo$1.foo()).&&(Foo.this.bar().==(Foo$1.bar())).&&(Foo$1.canEqual(Foo.this))
}));
def <init>(foo: String, bar: Int): Foo = {
Foo.this.foo = foo;
Foo.this.bar = bar;
Foo.super.<init>();
Foo.super./*Product*/$init$();
()
}
};
<synthetic> object Foo extends scala.runtime.AbstractFunction2 with Serializable {
final override <synthetic> def toString(): String = "Foo";
case <synthetic> def apply(foo: String, bar: Int): Foo = new Foo(foo, bar);
case <synthetic> def unapply(x$0: Foo): Option =
if (x$0.==(null))
scala.None
else
new Some(new Tuple2(x$0.foo(), scala.Int.box(x$0.bar())));
<synthetic> private def readResolve(): Object = Foo;
case <synthetic> <bridge> <artifact> def apply(v1: Object, v2: Object): Object = Foo.this.apply(v1.$asInstanceOf[String](), scala.Int.unbox(v2));
def <init>(): Foo.type = {
Foo.super.<init>();
()
}
}
...
Như chúng ta có thể thấy trình biên dịch Scala tạo ra một lớp Foovà đối tượng đồng hành thông thường Foo.
Chúng ta hãy đi qua lớp tổng hợp và nhận xét về những gì chúng ta đã có:
- trạng thái nội bộ của
Foolớp, bất biến:
val foo: String
val bar: Int
def foo(): String
def bar(): Int
def copy(foo: String, bar: Int): Foo
def copy$default$1(): String
def copy$default$2(): Int
- thực hiện
scala.Productđặc điểm:
override def productPrefix(): String
def productArity(): Int
def productElement(x$1: Int): Object
override def productIterator(): Iterator
- thực hiện
scala.Equalsđặc điểm để làm cho các trường hợp lớp trường hợp có thể so sánh cho bằng bằng ==:
def canEqual(x$1: Object): Boolean
override def equals(x$1: Object): Boolean
- ghi đè
java.lang.Object.hashCodecho việc tuân theo hợp đồng bằng mã băm:
override <synthetic> def hashCode(): Int
- ghi đè
java.lang.Object.toString:
override def toString(): String
- constructor để khởi tạo theo
newtừ khóa:
def <init>(foo: String, bar: Int): Foo
Đối tượng Foo: - phương thức applykhởi tạo mà không cần newtừ khóa:
case <synthetic> def apply(foo: String, bar: Int): Foo = new Foo(foo, bar);
- Phương thức trích xuất
unupplyđể sử dụng lớp trường hợp Foo trong khớp mẫu:
case <synthetic> def unapply(x$0: Foo): Option
- phương pháp để bảo vệ đối tượng dưới dạng singleton khỏi khử lưu huỳnh vì không cho phép tạo thêm một thể hiện:
<synthetic> private def readResolve(): Object = Foo;
- Đối tượng Foo mở rộng
scala.runtime.AbstractFunction2để thực hiện thủ thuật đó:
scala> case class Foo(foo:String, bar: Int)
defined class Foo
scala> Foo.tupled
res1: ((String, Int)) => Foo = scala.Function2$$Lambda$224/1935637221@9ab310b
tupled từ đối tượng trả về một funtion để tạo Foo mới bằng cách áp dụng một bộ gồm 2 phần tử.
Vì vậy, trường hợp lớp chỉ là cú pháp đường.