繁体   English   中英

Java接口:无法使已实现的方法受保护或私有

[英]Interfaces in Java: cannot make implemented methods protected or private

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

我希望我的已实现方法只能从自己的程序包中访问,因此我希望我的已实现方法受到保护。

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

有什么解决方法? 是否存在与此问题相关的设计模式?

在Java指南中,抽象类也无法完成任务。

阅读

“公共访问说明符表示该接口可以被任何程序包中的任何类使用。 如果您未指定该接口是公共的,则该接口只能被与该接口在同一程序包中定义的类访问 。”

那是你要的吗?

您的班级可以使用包保护,并且仍然可以实现一个接口:

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

如果您希望某些方法被保护/打包而其他方法则不被保护,这听起来您的类有多个责任,应将其划分为多个。

阅读对此评论和其他回复的评论后进行编辑:

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

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

哦,对决定我的示例的人应该使用K&R支撑:如果在服务条款中指定,请确保。 否则,您找不到与您的时间更好的事情了吗?

当我遇到这种情况时,我使用一个包可访问的内部或嵌套类来实现接口,从而将实现的方法从公共类中推出。

通常是因为我有一个带有特定公共API的类,该类必须实现其他功能才能完成工作(经常是因为其他东西是伪装成接口<grin>的回调)-这种情况在Comparable之类的事情上经常发生。 我不希望公共API被(强制公共)接口实现污染。

希望这可以帮助。

同样,如果您确实希望仅由包访问方法,则不需要受保护的范围说明符,而需要默认的(省略)范围说明符。 当然,使用protected将允许子类查看方法。

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

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

我知道接口必须是公共的

并非如此,您可以拥有带有默认访问修饰符的接口。

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

这里是:

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>

因此,实现所需的功能可防止在包外部使用接口和类。

这是使用抽象类完成的方法。

唯一的不便是它使您成为“子类”。

根据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()  );
    }
}

这是另一个受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对象上调用它。

我只是碰巧尝试构建受保护的方法,目的是仅在测试用例中使用它。 我想删除填充到数据库表中的测试数据。 无论如何,我都受到@Karl Giesing 帖子的启发。 不幸的是,它没有用。 我确实找到了一种使用受保护的内部类使其工作的方法。

界面:

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

然后将内部类定义为在公共类中受保护:

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

您想使用一个接口定义各种实现类可以公开的方法。 具有受保护方法的接口将无法达到该目的。

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

解决该问题的一种方法是(根据情况而定)仅制作一个匿名内部类,该内部类实现具有protected范围或private范围的接口。 例如:

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() { ... }
}

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

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

然后,您只能公开您想要的内容。

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

我只是创建一个抽象类。 没有任何伤害。

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

为了增加对Lambda表达式的支持,暂时考虑将对接口中私有方法的支持作为Java SE 8的一部分,但是为了支持Java SE 8更高优先级的任务,撤消了对它的支持。私有接口方法被采用,从而使得接口的非抽象方法能够在它们之间共享代码。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM