Поскольку черты - это не просто интерфейсы, им нужен какой-то способ для хранения своего внутреннего состояния.Но они должны быть совместимы с интерфейсами - так что они делают?Они создают средства доступа для того, что выглядит как поле (как вы можете видеть (среди прочего) с javap -l -s -c -private
в файлах классов):
public interface T1 extends java.lang.Object {
public abstract int T1$$v();
Signature: ()I
public abstract int getValueT1();
Signature: ()I
}
, а затем создаете класс реализации, который имеет статические методы для реализациифункциональность:
public abstract class T1$class extends java.lang.Object {
public static int getValueT1(T1);
Signature: (LT1;)I
Code:
0: aload_0
1: invokeinterface #12, 1; //InterfaceMethod T1.T1$$v:()I
6: ireturn
}
Теперь, надеюсь, понятно, что они будут разделены по умолчанию, поскольку эти сгенерированные внутри себя методы имеют имя признака в имени метода .И когда мы посмотрим на реализацию в T12
:
public class T12 extends java.lang.Object implements T1,T2,scala.ScalaObject {
private final int Overridden$T1$$v;
Signature: I
public final int T1$$v();
Signature: ()I
Code:
0: aload_0
1: getfield #22; //Field T1$$v:I
4: ireturn
public int getValueT1();
Signature: ()I
Code:
0: aload_0
1: invokestatic #29; //Method T1$class.getValueT1:(LT1;)I
4: ireturn
}
, вы увидите, что она просто заполняет то, что необходимо для каждой конкретной черты.Теперь вопрос - как черты когда-либо перезаписывают друг друга?Они кажутся совершенно разными!Это работа компилятора.Если что-то private
, оно скрыто и не может быть переопределено, поэтому не имеет значения, что другая (частная) вещь имеет то же имя.Но если это не так, компилятор жалуется на коллизию:
error: overriding value v in trait T1 of type Int;
value v in trait T2 of type Int needs `override' modifier
class T12 extends T1 with T2
, потому что теперь он не использует секретные искаженные имена со встроенным именем черты.(Обратите внимание, что getValueT1
не искажено в этом примере.)