Scala 如何解决;实现限制:特性。。。访问受保护的方法。。。在具体的特征方法中。”;

Scala 如何解决;实现限制:特性。。。访问受保护的方法。。。在具体的特征方法中。”;,scala,compiler-errors,mixins,protected,traits,Scala,Compiler Errors,Mixins,Protected,Traits,我正在使用的Java库类声明 protectedgetpage():页面{…} 现在我想制作一个助手Scala mixin来添加我经常使用的特性。我不想扩展这个类,因为Java类有不同的子类,我想在不同的地方扩展。问题是,如果我在mixintrait中使用getPage(),就会出现以下错误: 实现限制:traitMyMixin访问具体trait方法内部的受保护方法getPage 有没有一个解决方案可以让它在不影响我的子类的情况下工作?为什么会有这样的限制 到目前为止,我想出了一个解决办法:

我正在使用的Java库类声明

protectedgetpage():页面{…}
现在我想制作一个助手Scala mixin来添加我经常使用的特性。我不想扩展这个类,因为Java类有不同的子类,我想在不同的地方扩展。问题是,如果我在mixin
trait
中使用
getPage()
,就会出现以下错误:

实现限制:trait
MyMixin
访问具体trait方法内部的受保护方法
getPage

有没有一个解决方案可以让它在不影响我的子类的情况下工作?为什么会有这样的限制


到目前为止,我想出了一个解决办法:我重写trait中的方法

override def getPage(): Page = super.getPage();

这似乎有效,但我并不完全满意。幸运的是,我不需要在我的子类中重写
getPage()
,但如果需要,我会得到同一方法的两个重写,而这种解决方法将不起作用。

问题是,即使trait扩展了Java类,实现实际上也没有扩展Java类的内容。考虑

class A { def f = "foo" }
trait T extends A { def g = f + "bar" }
class B extends T { def h = g + "baz" }
B的实际字节码中,我们看到

public java.lang.String g();
  Code:
   0:   aload_0
   1:   invokestatic    #17; //Method T$class.g:(LT;)Ljava/lang/String;
   4:   areturn
这意味着它只是转发到一个名为
T$class
的东西,结果是

public abstract class T$class extends java.lang.Object{
public static java.lang.String g(T);
  Code:
  ...
因此,代码体根本不是从
a
的子类调用的

现在,使用Scala就没有问题了,因为它只是从字节码中省略了
protected
标志。但是
Java
强制只有子类才能调用受保护的方法

这样你就有了问题和信息

您无法轻松绕过此问题,尽管错误消息表明可能是最好的选择:

public class JavaProtected {
  protected int getInt() { return 5; }
}

scala> trait T extends JavaProtected { def i = getInt }
<console>:8: error: Implementation restriction: trait T accesses
      protected method getInt inside a concrete trait method.
  Add an accessor in a class extending class JavaProtected as a workaround.

有效。

谢谢,这就是我想要避免的,在我的子类中添加访问器。但现在我明白了为什么这是不可能的了。@PetrPudlák-你不必为每个子类都添加访问器,只需为原始类的一个启用访问器的子类添加访问器即可。然后,混合在trait中的所有其他类将扩展访问器启用类,而不是原始类。(当然,受保护的访问器将是接口的一部分,但至少您只需要编写一次。)问题是,我想将trait混合到Java类中,这些Java类的唯一公共超类位于Java库中。这就是为什么我想使用mixin特性来添加功能,而不必为我扩展的每个Java类创建Scala子类。@PetrPudlák-Ah。嗯,反射(在没有限制性安全管理器的环境中)将允许它。选择方法,调用
.setAccessible(true)
调用它,转换为正确的类型。我完全不建议这样做。
class WithAccessor extends JavaProtected { protected def myAccessor = getInt }
trait T extends WithAccessor { def i = myAccessor }