我知道界面必须是公开的。但是,我不希望这样。
我希望我的实现方法只能从他们自己的包中访问,所以我希望我的实现方法受到保护。
问题是我无法使接口或实现的方法受到保护。
什么是解决方法?是否存在与此问题相关的设计模式?
从Java指南中,抽象类也不能完成这项工作。
答案 0 :(得分:24)
答案 1 :(得分:11)
您的类可以使用程序包保护并仍然实现接口:
class Foo implements Runnable
{
public void run()
{
}
}
如果您希望某些方法受到保护/打包而其他方法没有,则听起来您的课程有多个职责,应该分成多个。
在阅读此评论及其他回复后进行编辑:
如果您以某种方式认为方法的可见性会影响调用该方法的能力,请再想一想。在没有走极端的情况下,您无法阻止某人使用反射来识别您的类的方法并调用它们。但是,这不是问题:除非有人试图破解您的代码,否则他们不会调用随机方法。
相反,将private / protected方法视为定义子类的契约,并使用接口来定义与外部世界的契约。
哦,对于那个决定我的例子的人应该使用K& R支撑:如果它在服务条款中有规定,那么肯定。否则,你不能找到更好的时间吗?
答案 2 :(得分:8)
当我遇到这种情况时,我使用一个包可访问的内部或嵌套类来实现接口,将实现的方法推出公共类。
通常是因为我有一个具有特定公共API的类,它必须实现其他功能才能完成工作(通常因为其他东西是伪装成接口的回调< grin>) - 这种情况发生了很多像可比的东西。我不希望公共API被(强制公共)接口实现污染。
希望这有帮助。
此外,如果您确实希望仅由包访问的方法,则不需要受保护的范围说明符,您需要默认(省略)范围说明符。当然,使用protected will会允许子类查看方法。
BTW,我认为界面方法被推断为公共的原因是因为拥有一个只在同一个包中的类实现的接口是非常例外的。它们通常被另一个包中的某些东西所调用,这意味着它们需要公开。答案 3 :(得分: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>
因此,实现您想要的,防止包外的接口和类使用。
答案 4 :(得分: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() );
}
}
答案 5 :(得分: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
对象上调用它。
答案 6 :(得分:1)
我刚刚遇到这个尝试构建一个受保护的方法,意图只在测试用例中使用它。我想删除我填入数据库表的测试数据。无论如何,我受@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
答案 7 :(得分:0)
你可以使用封装而不是继承。
也就是说,创建你的类(不会继承任何东西),并在其中有一个你想要扩展的对象的实例。
然后你只能暴露你想要的东西。
这样做的明显缺点是你必须明确地传递你想要暴露的所有东西的方法。它不会是一个子类......
答案 8 :(得分:0)
我只想创建一个抽象类。没有任何伤害。
答案 9 :(得分:0)
使用接口,您可以定义可由各种实现类公开的方法。 拥有受保护方法的接口不会达到这个目的。
我猜你的问题可以通过重新设计你的类层次结构来解决。
答案 10 :(得分:0)
解决这个问题的一种方法是(根据具体情况)创建一个匿名内部类,实现具有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() { ... }
}
答案 11 :(得分:0)
我想你现在可以在Java 9版本中使用它了。从Java 9的openJdk笔记,
简要考虑了对接口中私有方法的支持 包含在Java SE 8中作为添加支持的努力的一部分 Lambda表达式,但被撤回,以便更好地专注于更高 Java SE 8的优先级任务。现在建议支持 采用私有接口方法,从而实现非抽象 接口的方法,以在它们之间共享代码。