Scala:将特征与私人领域混合

Vil*_*tas 7 scala multiple-inheritance traits

这不是一个问题,而是让我感到非常兴奋!我写这个小例子只是为了证明相反 - 我预计编译器错误或其中一个值(111或222,我不确定).

scala> trait T1 { private val v = 111; def getValueT1 = v }
scala> trait T2 { private val v = 222; def getValueT2 = v }
scala> class T12 extends T1 with T2                        
scala> val t = new T12                                     
scala> t.getValueT1                                        
res9: Int = 111
scala> t.getValueT2                                        
res10: Int = 222
Run Code Online (Sandbox Code Playgroud)

为什么不v被覆盖?当然,这只有vs是私有的,但仍然是有效的.

Rex*_*err 15

由于traits不仅仅是接口,它们还需要一些方法来存储它们的内部状态.但它们必须与接口兼容 - 那么他们做了什么?它们为看起来像字段的东西创建访问器(正如您可以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
}
Run Code Online (Sandbox Code Playgroud)

然后创建一个具有静态方法来实现该功能的实现类:

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

现在,希望很明显,默认情况下这些是独立的,因为这些内部生成的方法方法名称中具有特征的名称.当我们查看实施时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
}
Run Code Online (Sandbox Code Playgroud)

你可以看到它只是填补了每个特定特征所需的内容.现在的问题是-如何特质永远互相覆盖?他们似乎是完全分开的!这是编译器的工作.如果某些东西被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
Run Code Online (Sandbox Code Playgroud)

因为现在它没有使用嵌入了特征名称的秘密错位名称.(注意getValueT1在这个例子中没有被破坏.)


Dan*_*ral 6

这不是特质特有的属性.例如:

scala> class X {
     |   private val v = 111
     |   def getX = v
     | }
defined class X

scala> class Y extends X {
     |   private val v = 222
     |   def getY = v
     | }
defined class Y

scala> new Y
res0: Y = Y@5ca801b0

scala> res0.getX
res1: Int = 111

scala> res0.getY
res2: Int = 222
Run Code Online (Sandbox Code Playgroud)

在Java中也是如此.私有成员私有.它们只属于它们被定义的地方,并且在外面没有任何影响.如果通过继承发生冲突,那么它们就会被看到,这会破坏私有化的目的.