Java中的接口:无法使已实现的方法受到保护或私有
我知道接口必须是公共的。 但是,我不希望这样。
我希望我的实现方法只能从他们自己的包中访问,所以我希望我的实现方法受到保护。
问题是我不能使接口或实现的方法受到保护。
什么是解决方法? 是否存在与此问题相关的设计模式?
从Java指南中,抽象类也不能完成这项工作。
读这个 。
“公共访问说明符指示任何包中的任何类都可以使用该接口。 如果未指定接口是公共接口,则只能在与接口相同的包中定义的类中访问您的接口 。”
那是你要的吗?
您的类可以使用包保护并仍然实现一个接口:
class Foo implements Runnable { public void run() { } }
如果你想要一些方法来保护/包而不是其他方法,听起来你的类有多个责任,应该分成多个。
阅读此评论和其他回复后编辑:
如果您以某种方式认为方法的可见性会影响调用该方法的能力,请再想一想。 在没有走极端的情况下,您无法阻止某人使用reflection来识别您的类的方法并调用它们。 但是,这不是问题:除非有人试图破解您的代码,否则他们不会调用随机方法。
相反,将private / protected方法视为定义子类的契约,并使用接口来定义与外部世界的契约。
哦,对于决定我的例子的人应该使用K&R支撑:如果它在服务条款中规定,当然。 否则,你不能找到更好的时间吗?
当我遇到这种情况时,我使用一个包可访问的内部或嵌套类来实现接口,将实现的方法推出公共类。
通常这是因为我有一个具有特定公共API的类,它必须实现其他东西来完成它的工作(通常是因为其他东西是伪装成接口
希望这可以帮助。
此外,如果您确实希望仅由包访问的方法,则不需要受保护的范围说明符,您需要默认(省略)范围说明符。 当然,使用protected will会允许子类查看方法。
顺便说一句,我认为界面方法被推断为公共的原因是因为拥有一个只在同一个包中的类实现的接口是非常例外的; 它们通常被另一个包中的某些东西调用,这意味着它们需要公开。
这个问题基于错误的陈述:
我知道接口必须是公共的
不是,您可以使用默认访问修饰符的接口。
问题是我不能使接口或实现的方法受到保护
这里是:
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的post的启发。 不幸的是它没有用。 我确实想方设法让它使用受保护的内部类。
界面:
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(); } }
然后,您只能从同一个包中的其他类访问受保护的方法,因为我的测试代码如show所示:
package foo; public class FooTest { MyFoo myFoo = new MyFoo(); void doProtectedFoo() { myFoo.pFoo = myFoo.gimmeFoo(); myFoo.pFoo.doSomeFoo(); } }
对于原始海报来说有点晚了,但是,嘿,我刚刚发现它。 :d
你可以使用封装而不是inheritance。
也就是说,创建你的类(不会inheritance任何东西),并在其中有一个你想要扩展的对象的实例。
然后你只能暴露你想要的东西。
这样做的明显缺点是您必须为要暴露的所有内容显式传递方法。 它不会是一个子类……
我只想创建一个抽象类。 没有任何伤害。
使用接口,您需要定义可由各种实现类公开的方法。 拥有受保护方法的接口不会达到此目的。
我猜你的问题可以通过重新设计你的类层次结构来解决。
解决这个问题的一种方法是(根据具体情况)制作一个匿名内部类,实现具有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 Expressions的支持的努力的一部分,简要考虑了对接口中的私有方法的支持,但是为了更好地专注于Java SE 8的更高优先级任务而被撤回。现在提议支持对于私有接口方法,从而使接口的非抽象方法能够在它们之间共享代码。
参考https://bugs.openjdk.java.net/browse/JDK-8071453