Scala:将特征与私有字段混合

发布于 2024-10-20 04:44:25 字数 599 浏览 1 评论 0原文

这不是什么大问题,而是我很兴奋,因为这是可能的!我写这个小例子只是为了证明相反的情况 - 我预计要么是编译器错误,要么是其中一个值(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

为什么 v 没有被覆盖?当然,只有当 v 是私有的时,这才有效,但仍然如此。

It's not much of a question, it's rather my excitement that it's possible at all! I wrote this little example just to prove the opposite - I expected either a compiler error or one of the values (111 or 222, I wasn't sure).

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

Why doesn't the v get overridden? Off course this works only as long as vs are private, but still.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

旧城烟雨 2024-10-27 04:44:25

由于特征不仅仅是接口,它们需要某种方式来存储其内部状态。但它们必须与接口兼容——那么它们是做什么的呢?他们为看起来像字段的内容创建访问器(正如您可以在类文件上使用 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
}

您可以看到它只是填充了每个特定特征所需的内容。现在的问题是——特征如何相互覆盖?他们似乎是完全分开的!这是编译器的工作。如果某些内容是私有,那么它是隐藏的并且无法被覆盖,因此另一个(私有)内容具有相同的名称并不重要。但如果不是,编译器会抱怨冲突:

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 未受到损坏。)

Since traits are not just interfaces, they need some way to store their internal state. But they have to be compatible with interfaces--so what do they do? They create accessors for what looks like a field (as you can see (among other things) with javap -l -s -c -private on the class files):

public interface T1 extends java.lang.Object {
public abstract int T1$v();
Signature: ()I

public abstract int getValueT1();
Signature: ()I
}

and then create an implementation class that has static methods to implement the functionality:

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
}

Now, hopefully, it's clear that these would be separate by default since these internally-generated methods have the name of the trait in the name of the method. And when we look in the implementation in 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
}

you can see that it just fills in what's needed for each specific trait. Now the question is--how do traits ever overwrite each other? They seem to be completely separate! That's the compiler's job. If something is private it's hidden and can't be overridden, so it doesn't matter that another (private) thing has the same name. But if it's not, the compiler complains of a collision:

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

because now it's not using the secret mangled names with the trait name embedded. (Observe that getValueT1 is not mangled in this example.)

愿与i 2024-10-27 04:44:25

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

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

在 Java 中也是如此。私人成员是私人。它们只属于定义它们的地方,对外部没有影响。如果通过继承发生冲突,它们将是可见的,这将违背私有的目的。

This is not a property particular to traits. For instance:

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

And the same holds true in Java. Private members are private. They belong solely to where they were defined, and have no effect outside. If there was a conflict through inheritance, they would be visible, which would defeat the purpose of being private.

乱世争霸 2024-10-27 04:44:25

私有成员和方法不能被重写。这是为了防止后代注入的类行为发生变化。这里的概念与 C++ 非常相似 - 每个祖先都拥有自己的成员副本,直到调用特殊方法(例如虚拟继承)为止。

Private members and methods can't be overridden. It is to prevent changes in class behaviour injected by descendants. The concept here is very simlar to C++ one - each ancestor holds its own copy of members until a special methods (virtual inheritance, for example) is invoked.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文