【问题标题】:How to implement an interface on a protected java class如何在受保护的 java 类上实现接口
【发布时间】:2011-06-12 04:16:03
【问题描述】:

我希望在包私有 java 类上实现一个接口,但我在实现这一点时遇到了一些困难。下面是一个例子。

class Foo
{
    String something(String str)
    {
        return ""str+"!";
    }
}




public interface Bar
{
    String something(String str);
}

这里最好的方法是什么?我的最终目标是在 Foo 类上实现 Bar 接口。我希望能够将 Foo 转换为 Bar: (Bar)Foo

Bar 接口和 Foo 类位于不同的包中。有没有办法做到这一点?

请指教。

【问题讨论】:

    标签: java class interface visibility protected


    【解决方案1】:

    Foo 需要实现 Bar

    protected class Foo implements Bar

    另外,我认为 Foo.something 需要 public 才能实现 Bar.something

    旁注:虽然这可能只是一个例子,

    return ""str+"!";

    应该是:

    return str + "!";

    如果 Foo 是包私有的,而您无权访问源代码,只有类文件和/或包含 Foo.class 的 jar,则没有什么可做的 - 包私有的东西对中的类是不可见的默认包(没有指定包的地方)和其他包。

    【讨论】:

    • Foo.something 不公开,我无权访问
    • 你知道 Foo.something 是否至少受到保护?根据你的例子, Foo.something 是包可见的,我不知道我们能做多少。
    • @andersra:“我无权访问”是什么意思?
    • Foo 是包私有的,接口在另一个包中。我编辑了原始问题以反映这一点,抱歉。
    【解决方案2】:

    如果您无法控制某个类,但您想让它看起来像您拥有的 API,那么您可以 Adapt 它来满足您的需求。提示:适配器模式

    【讨论】:

      【解决方案3】:

      如果您无权访问Foo 的源代码,则需要使用继承或组合。

      // By logically including your code in the package containing Foo,
      // you can now access it. If Foo belongs to the default package, sorry.
      // This also doesn't work if the package is sealed.
      package where.foo.resides;
      
      public interface Bar {
          String something(String s);
      }
      
      // Inheritance
      public class FooBar extends Foo implements Bar {
          public String something(String s) {
              return super.something(s);
          }
      }
      
      // Composition
      public class ComposedFooBar implements Bar {
          private final Foo delegate;
          public ComposedFooBar(Foo delegate) {
              this.delegate = delegate;
          }
          public String something(String s) {
              return delegate.something(s);
          }
      }
      

      【讨论】:

      • 我的错误,如果 Foo 是包私有的,这个解决方案是否仍然适用?
      • 视情况而定。如果Foo 在一个密封的JAR 文件中并且您没有源代码,那么您就不走运(没有反射),因为您无法在其包之外引用Foo 类型。情况可能并非如此,因此您仍然可以创建一个以package foo; 或任何包含Foo 的包开头的文件并使用这种方法。
      【解决方案4】:

      你不能。让包级别访问它以精确避免在外面看到该类。但是,您可以做的事情(授予 Foo 不是最终的)是这样的:

      C:\>type *.java
      //Foo.java
      package foo;
      class Foo {
        String something( String s ) {
          return s + "!";
        }
      }  
      //Bar.java
      package bar;
      public interface Bar {
        public String something( String s );
      }    
      //Baz.java
      package foo;    
      import bar.Bar;    
      public class Baz extends Foo implements Bar {
        // make sure you're overriding
        @Override
        public String something ( String s ) {
          return super.something( s );
        }
      }     
      //Use it: Main.java
      package bar;
      import foo.Baz;   
      class Main {
        public static void main( String ... args ) {
          Bar bar = new Baz();
          System.out.println( bar.something("like this?"));
        }
      }
      
      C:\>java bar.Main
      like this?!
      

      哒哒!

      诀窍是在与父级相同的包中定义子级,以便您可以创建它的公共版本。

      我希望这会有所帮助。

      【讨论】:

      • 这是我最初采用的方法,但我收到错误消息:“Foo 中的某物(字符串)无法在 Bar 中实现某物(字符串),试图分配较弱的访问权限;是公开的
      • 我也明白了。然后刚刚添加:public String something( String s ) { return super.something( s ); }您可以复制我提供的代码并自己查看。
      • 这就是为什么有必要用返回super.something(s)的公共版本覆盖something(s)。
      • 可能你拼错了覆盖的方法添加Override注解。查看更新
      【解决方案5】:

      您可以尝试通过 BCEL 或 ASM 使用字节码注入,并在运行时设置接口。不过,这很棘手。

      也许还有一种方法可以通过反射来改变交互,但我对此表示怀疑。

      私人存在是有原因的。

      【讨论】:

      • 我认为这行不通。字节码注入方法很可能导致VerifyError 或IncompatibleClassChangeError。此外,您不能通过反射来更改接口......但您可以反射地调用私有方法。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-11-17
      • 2011-07-19
      • 2013-04-07
      • 2013-09-02
      • 1970-01-01
      • 2010-09-30
      • 1970-01-01
      相关资源
      最近更新 更多