【问题标题】:Interfaces in Java: cannot make implemented methods protected or privateJava中的接口:不能使实现的方法受保护或私有
【发布时间】:2010-09-30 04:44:31
【问题描述】:

我知道接口必须是公共的。但是,我不希望那样。

我希望我实现的方法只能从它们自己的包中访问,所以我希望我实现的方法受到保护。

问题是我无法使接口或实现的方法受到保护。

什么是变通方法?是否有与此问题相关的设计模式?

根据 Java 指南,抽象类也无法完成这项工作。

【问题讨论】:

  • 抽象类有什么问题(除了让你子类化?)
  • "如果抽象类只包含抽象方法声明,则应将其声明为接口。"我没有质疑这背后的原因,但我想我应该。
  • Java 指南通过提供很好的建议指导您。这不是规则。
  • 大多数时候是的,但这是你不一定的时候之一
  • 公开接口不是必须的。好心的人,编辑问题以使事情清楚。谢谢。

标签: java interface access-specifier


【解决方案1】:

阅读this

“公共访问说明符表示该接口可以被任何包中的任何类使用。如果您不指定该接口是公共的,那么您的接口将只能被定义在与相同包中的类访问界面。”

这是你想要的吗?

【讨论】:

  • 我认为在接口本身的可见性和接口方法的可见性之间存在一些混淆。您可以将接口设为非公开,但方法将始终公开。
  • @Jon : “方法将永远是公开的” 背后的原因/想法是什么?
  • @M-D:说实话,我不知道。
  • @M-D,没有什么特别的原因,很可能只是这样决定的(stackoverflow.com/a/5377300/632951),就像how static abstract got ruled out arbitrarily一样。
【解决方案2】:

你的类可以使用包保护并且仍然实现一个接口:

class Foo implements Runnable 
{
    public void run()
    {
    }
}

如果您希望某些方法受到保护/打包,而另一些则不,听起来您的类有多个职责,应该拆分为多个。

在阅读 cmets 对此和其他回复后进行编辑:

如果您以某种方式认为方法的可见性会影响调用该方法的能力,请再想一想。如果不走极端,您就不能阻止某人使用反射来识别您的类的方法并调用它们。但是,这不是问题:除非有人试图破解您的代码,否则他们不会调用随机方法。

相反,将私有/受保护方法视为定义子类的契约,并使用接口定义与外界的契约。

哦,对于决定我的示例应该使用 K&R 支撑的人:如果服务条款中指定了它,当然可以。否则,你就不能找到更好的事情来利用你的时间吗?

【讨论】:

  • 好点! +1 虽然接口是公共的,但实现可以是“默认”访问修饰符。在我看来这是正确的答案! :)
  • 我不明白这个答案。由于 run 是公共的,它可以从任何包中调用,对吧?我不希望从其他包中调用我实现的方法。
  • 但是你调用它的类只在包中可见。你在一个不公开的特定实例上调用 run。
  • 哦,我明白了。是的,我想这就是我要找的。谢谢大家。
  • @jbu -- 如果这个答案确实是你想要的,你应该接受它......
【解决方案3】:

当我反对这一点时,我使用包可访问的内部或嵌套类来实现接口,将实现的方法推出公共类。

通常这是因为我有一个具有特定公共 API 的类,它必须实现其他东西才能完成工作(通常是因为其他东西是伪装成接口 的回调) - 这种情况经常发生像可比的。我不希望公共 API 被(强制公共)接口实现污染。

希望这会有所帮助。

另外,如果你真的想要只被包访问的方法,你不需要受保护的范围说明符,你需要默认的(省略的)范围说明符。当然,使用 protected 将允许子类看到方法。

顺便说一句,我认为接口方法被推断为公共的原因是因为只有同一个包中的类实现的接口是非常例外的;它们最常被另一个包中的某些东西调用,这意味着它们需要公开。

【讨论】:

    【解决方案4】:

    这个问题是基于一个错误的陈述:

    我知道接口必须是公开的

    不是真的,你可以拥有带有默认访问修饰符的接口。

    问题是我无法保护接口或实现的方法

    这里是:

    C:\oreyes\cosas\java\interfaces>type a\*.java
    a\Inter.java
    package a;
    
    interface Inter {
        public void face();
    }
    
    a\Face.java
    package a;
    
    class Face implements Inter {
        public void face() {
            System.out.println( "face" );
        }
    }
    
    
    C:\oreyes\cosas\java\interfaces>type b\*.java
    b\Test.java
    
    package b;
    import a.Inter;
    import a.Face;
    
    public class Test {
        public static void main( String [] args ) {
            Inter inter = new Face();
            inter.face();
        }
    }
    
    C:\oreyes\cosas\java\interfaces>javac -d . a\*.java b\Test.java
    b\Test.java:2: a.Inter is not public in a; cannot be accessed from outside package
    import a.Inter;
            ^
    b\Test.java:3: a.Face is not public in a; cannot be accessed from outside package
    import a.Face;
            ^
    b\Test.java:7: cannot find symbol
    symbol  : class Inter
    location: class b.Test
            Inter inter = new Face();
            ^
    b\Test.java:7: cannot find symbol
    symbol  : class Face
    location: class b.Test
            Inter inter = new Face();
                              ^
    4 errors
    
    C:\oreyes\cosas\java\interfaces>
    

    因此,实现您想要的,防止在包外使用接口和类。

    【讨论】:

    • 开,“你可以拥有带有默认访问修饰符的接口”...不,所有接口方法都被推断为公共的;事实上,指定可见范围是无关紧要的,并且被忽略了。
    • @LawrenceDol 我从来没有说过,在示例中,即使方法被显式标记为公共,但接口不是公共的,所以它的方法无法访问包,因此使它们有效地包保护.
    • 啊,对不起,我看错了你写的东西。我错误地认为它是“你可以拥有带有默认访问修饰符的接口 [方法]”。
    【解决方案5】:

    这是使用抽象类的方法。

    唯一不方便的是它让你成为“子类”。

    根据 java 指南,您应该“大部分”时间都遵循该建议,但我认为在这种情况下会没问题。

    public abstract class Ab { 
        protected abstract void method();
        abstract void otherMethod();
        public static void main( String [] args ) { 
            Ab a = new AbImpl();
            a.method();
            a.otherMethod();
        }
    }
    class AbImpl extends Ab {
        protected void method(){
            System.out.println( "method invoked from: " + this.getClass().getName() );
        }
        void otherMethod(){ 
            System.out.println("This time \"default\" access from: " + this.getClass().getName()  );
        }
    }
    

    【讨论】:

      【解决方案6】:

      这是另一个解决方案,灵感来自 C++ Pimpl 习语。

      如果您想实现一个接口,但不希望该实现公开,您可以创建一个实现该接口的匿名内部类的组合对象。

      这是一个例子。假设你有这个界面:

      public interface Iface {
          public void doSomething();
      }
      

      您创建一个Iface 类型的对象,并将您的实现放入其中:

      public class IfaceUser {
          private int someValue;
          // Here's our implementor
          private Iface impl = new Iface() {
              public void doSomething() {
                  someValue++;
              }
          };
      }
      

      当您需要调用 doSomething() 时,您可以在您组合的 impl 对象上调用它。

      【讨论】:

      • 我喜欢这个解决方案,虽然我认为它使代码看起来很乱,但它以最可扩展的方式解决了问题。
      【解决方案7】:

      我只是在尝试构建一个受保护的方法时遇到这种情况,目的是只在测试用例中使用它。我想删除填充到数据库表中的测试数据。无论如何,我的灵感来自@Karl Giesingpost。不幸的是,它没有用。我确实想出了一种使用受保护的内部类使其工作的方法。

      界面:

      package foo;
      interface SomeProtectedFoo {
          int doSomeFoo();
      }
      

      那么在public class中定义为protected的内部类:

      package foo;
      public class MyFoo implements SomePublicFoo {
          // public stuff
          protected class ProtectedFoo implements SomeProtectedFoo {
              public int doSomeFoo() { ... }
          }
          protected ProtectedFoo pFoo;
          protected ProtectedFoo gimmeFoo() {
              return new ProtectedFoo();
          }
      }
      

      然后您只能从同一个包中的其他类访问受保护的方法,因为我的测试代码如下所示:

      package foo;
      public class FooTest {
          MyFoo myFoo = new MyFoo();
          void doProtectedFoo() {
              myFoo.pFoo = myFoo.gimmeFoo();
              myFoo.pFoo.doSomeFoo();
          }
      }
      

      原始海报有点晚了,但是,我刚刚找到了。 :D

      【讨论】:

      • 是的,对不起,我的帖子只是给出一个大致的想法,而不是提供全功能的代码。但是,嘿,至少我启发了某人。 :)
      • 当我无法从 stackoverflow 复制粘贴代码时,我的书呆子气很强烈。 :D
      【解决方案8】:

      您可以使用封装而不是继承。

      也就是说,创建您的类(它不会继承任何东西)并在其中包含您要扩展的对象的实例。

      那么你可以只公开你想要的。

      这样做的明显缺点是您必须显式地为要公开的所有内容传递方法。而且它不会是子类...

      【讨论】:

        【解决方案9】:

        我只想创建一个抽象类。没有坏处。

        【讨论】:

        • 你怎么能这么说?!抽象类是万恶之源! :D
        【解决方案10】:

        对于一个接口,您希望定义可以由各种实现类公开的方法。 拥有一个带有受保护方法的接口并不能达到这个目的。

        我猜你的问题可以通过重新设计你的类层次结构来解决。

        【讨论】:

          【解决方案11】:

          解决此问题的一种方法是(视情况而定)只创建一个匿名内部类来实现具有protectedprivate 范围的接口。例如:

          public class Foo {
              interface Callback {
                  void hiddenMethod();
              }
          
              public Foo(Callback callback) {
              }
          }
          

          那么在Foo的用户中:

          public class Bar {
              private Foo.Callback callback = new Foo.Callback() { 
                  @Override public void hiddenMethod() { ... }
              };
              private Foo foo = new Foo(callback);
          }
          

          这样可以避免以下情况:

          public class Bar implements Foo.Callback {
              private Foo foo = new Foo(this);
          
              // uh-oh! the method is public!
              @Override public void hiddenMethod() { ... }
          }
          

          【讨论】:

            【解决方案12】:

            我认为你现在可以在 Java 9 版本中使用它。来自 Java 9 的 openJdk 注释,

            曾简要考虑过对接口中的私有方法的支持 包含在 Java SE 8 中,作为增加对 Lambda 表达式,但被撤回以更好地专注于更高 Java SE 8 的优先任务。现在建议支持 采用私有接口方法,从而实现非抽象 接口的方法在它们之间共享代码。

            参考https://bugs.openjdk.java.net/browse/JDK-8071453

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2013-04-07
              • 2010-11-17
              • 2013-09-02
              • 1970-01-01
              • 2012-05-19
              • 2011-10-07
              • 1970-01-01
              • 2011-07-09
              相关资源
              最近更新 更多