To jest interesujące! Jeśli umieścisz definicje klas do pliku i skompilować go za pomocą scalac -print test.scala
widać coś takiego,
[[syntax trees at end of cleanup]] // scala
package <empty> {
class A extends Object {
def g(): String = A.f();
def <init>(): A = {
A.super.<init>();
()
}
};
object A extends Object {
private[this] val f: String = _;
<stable> <accessor> def f(): String = A.this.f;
def <init>(): A.type = {
A.super.<init>();
A.this.f = "Object A";
()
}
};
class B extends A {
<synthetic> private[this] val x$1: runtime.BoxedUnit = _;
def <init>(): B = {
B.super.<init>();
B.this.x$1 = {
case <synthetic> val x1: String = ("Object B": String("Object B"));
case5(){
if (A.f().==(x1))
{
val x2: String = x1;
matchEnd4(scala.runtime.BoxedUnit.UNIT)
}
else
case6()
};
case6(){
matchEnd4(throw new MatchError(x1))
};
matchEnd4(x: runtime.BoxedUnit){
scala.runtime.BoxedUnit.UNIT
}
};
()
}
}
}
To pokazuje, że kompilator tworzy klasę B
z inicjalizacji, który wykonuje mecz sprawdzając, że wartości użyte w override val A.f
jest równa oryginalnej wartości if (A.f().==(x1))
. Czy nie wydaje się zbyt przydatne, prawda? Jeśli nie są równe, zgłasza błąd dopasowania, dzwoniąc pod numer case6()
. Możemy to potwierdzić, zmieniając definicję class B
na override val A.f = "Object A"
.
class B extends A {
override val A.f = "Object A"
}
scala> val b = new B
b: B = [email protected]
Jak to naprawić? Można to zrobić tylko,
class B extends A {
override def g = "Object B"
}
scala> val b = new B
b: B = [email protected]
scala> b.g
res1: String = Object B
lub
class B extends A {
val f = "Object B"
}
scala> val b = new B
b: B = [email protected]
scala> b.f
res0: String = Object B
Dzięki za wyjaśnienie! Zgadzam się z tobą na temat potrzeby generowania nadrzędnych obiektów towarzyszących, ale powodem, dla którego chcę to zrobić, jest testowanie, w którym chcę zastąpić metodę wewnątrz obiektu towarzyszącego inną metodą. Ponadto niektóre języki umożliwiają nadpisywanie metod statycznych. – deepkimo