29

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

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

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

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

从 Java 指南来看,抽象类也无法完成这项工作。

4

12 回答 12

25

这个

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

那是你要的吗?

于 2009-01-08T02:29:13.243 回答
11

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

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

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

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

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

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

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

于 2009-01-08T02:29:51.743 回答
8

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

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

希望这可以帮助。

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

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

于 2009-01-08T03:02:09.527 回答
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>

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

于 2009-01-13T06:31:08.533 回答
3

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

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

根据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()  );
    }
}
于 2009-01-08T02:30:09.933 回答
1

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

于 2014-06-24T19:51:27.303 回答
1

我刚刚遇到这个试图构建一个受保护的方法,目的是只在测试用例中使用它。我想删除填充到数据库表中的测试数据。无论如何,我受到@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

于 2014-12-02T23:59:41.297 回答
0

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

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

然后你可以只暴露你想要的。

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

于 2009-01-08T02:28:10.140 回答
0

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

于 2009-01-08T02:44:53.757 回答
0

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

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

于 2012-12-12T13:01:19.303 回答
0

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

接口中的私有方法支持曾一度考虑包含在 Java SE 8 中,作为增加对 Lambda 表达式支持的努力的一部分,但为了更好地专注于 Java SE 8 的更高优先级任务而被撤回。现在建议支持对于私有接口方法,从而使接口的非抽象方法能够在它们之间共享代码。

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

于 2017-09-21T10:59:03.353 回答
0

解决这个问题的一种方法是(取决于情况)只创建一个匿名内部类来实现具有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() { ... }
}
于 2016-04-12T22:53:42.703 回答