【问题标题】:How to solve "Implementation restriction: trait ... accesses protected method ... inside a concrete trait method."如何解决“实施限制:特征......访问受保护的方法......在具体的特征方法中。”
【发布时间】:2013-07-07 13:56:39
【问题描述】:

我正在使用的 Java 库类声明

protected getPage(): Page { ... }

现在我想制作一个辅助 Scala mixin 来添加我经常使用的功能。我不想扩展这个类,因为Java类有不同的子类我想在不同的地方扩展。问题是,如果我在我的 mixin trait 中使用 getPage(),我会收到此错误:

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

有没有办法让它工作而不影响我的子类?为什么会有这个限制?


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

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

这似乎可行,但我并不完全满意。幸运的是,我不需要在我的子类中覆盖 getPage(),但如果需要,我会获得相同方法的两个覆盖,但这种解决方法将不起作用。

【问题讨论】:

    标签: scala compiler-errors mixins protected traits


    【解决方案1】:

    问题在于,即使 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.
    

    注意最后一行。

    class WithAccessor extends JavaProtected { protected def myAccessor = getInt }
    trait T extends WithAccessor { def i = myAccessor }
    

    有效。

    【讨论】:

    • 谢谢,这是我想避免的,将访问器添加到我的子类中。但现在我明白为什么不可能了。
    • @PetrPudlák - 您不必将访问器添加到 每个 子类,只需添加到 一个 启用访问器的原始子类。然后,所有其他混入特征的类将扩展访问器启用类而不是原始类。 (当然,受保护的访问器将成为接口的一部分,但至少您只需编写一次。)
    • 问题是我想将 trait 混合到 Java 类中,其唯一的公共超类在 Java 库中。这就是为什么我想使用 mixin trait 来添加功能,而不必为我扩展的每个 Java 类创建一个 Scala 子类。
    • @PetrPudlák - 啊。好吧,反射(在没有限制性安全管理器的环境中)将允许它。选择方法,调用.setAccessible(true)invoke 它,转换为正确的类型。我根本不推荐这个。
    猜你喜欢
    • 2023-03-13
    • 2016-04-17
    • 2013-10-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-22
    相关资源
    最近更新 更多