我希望能够在一个包中编写一个Java类,它可以访问另一个包中类的非公共方法,而不必使它成为另一个类的子类。这可能吗?
当前回答
据我所知,这是不可能的。
也许,你可以给我们更多关于你的设计的细节。像这样的问题很可能是设计缺陷造成的。
只考虑
如果这些类如此密切相关,为什么它们在不同的包中? A是否访问B的私有成员,或者操作是否应该移动到类B并由A触发? 这是真正的调用还是事件处理更好?
其他回答
如果你想访问受保护的方法,你可以创建一个你想要使用的类的子类,它将你想要使用的方法公开为公共的(或者是更安全的命名空间内部的),并在你的类中有一个类的实例(将它用作代理)。
就私人方法而言(我认为)你运气不好。
例如,“朋友”概念在Java中很有用,可以将API与其实现分开。实现类通常需要访问API类的内部内容,但这些内容不应该公开给API客户端。这可以使用“朋友访问器”模式来实现,如下所示:
通过API公开的类:
package api;
public final class Exposed {
static {
// Declare classes in the implementation package as 'friends'
Accessor.setInstance(new AccessorImpl());
}
// Only accessible by 'friend' classes.
Exposed() {
}
// Only accessible by 'friend' classes.
void sayHello() {
System.out.println("Hello");
}
static final class AccessorImpl extends Accessor {
protected Exposed createExposed() {
return new Exposed();
}
protected void sayHello(Exposed exposed) {
exposed.sayHello();
}
}
}
提供'friend'功能的类:
package impl;
public abstract class Accessor {
private static Accessor instance;
static Accessor getInstance() {
Accessor a = instance;
if (a != null) {
return a;
}
return createInstance();
}
private static Accessor createInstance() {
try {
Class.forName(Exposed.class.getName(), true,
Exposed.class.getClassLoader());
} catch (ClassNotFoundException e) {
throw new IllegalStateException(e);
}
return instance;
}
public static void setInstance(Accessor accessor) {
if (instance != null) {
throw new IllegalStateException(
"Accessor instance already set");
}
instance = accessor;
}
protected abstract Exposed createExposed();
protected abstract void sayHello(Exposed exposed);
}
从'friend'实现包中的类的访问示例:
package impl;
public final class FriendlyAccessExample {
public static void main(String[] args) {
Accessor accessor = Accessor.getInstance();
Exposed exposed = accessor.createExposed();
accessor.sayHello(exposed);
}
}
Eirikma的回答简单而出色。我可能还要补充一点:与其使用一个公共可访问的方法getFriend()来获取一个不能使用的朋友,不如更进一步,不允许获取没有令牌的朋友:getFriend(Service.FriendToken)。这个FriendToken将是一个具有私有构造函数的内部公共类,因此只有Service可以实例化一个。
我认为c++中的友类就像Java中的内部类概念。使用内部类 实际上可以定义一个外围类和一个封闭类。封闭类具有对其封闭类的public和private成员的完全访问权。 请看下面的链接: http://docs.oracle.com/javase/tutorial/java/javaOO/nested.html
下面是一个具有可重用Friend类的清晰用例示例。这种机制的好处是使用简单。也许给单元测试类比应用程序的其他部分更多的访问权是好的。
首先,这里有一个如何使用Friend类的示例。
public class Owner {
private final String member = "value";
public String getMember(final Friend friend) {
// Make sure only a friend is accepted.
friend.is(Other.class);
return member;
}
}
然后在另一个包中你可以这样做:
public class Other {
private final Friend friend = new Friend(this);
public void test() {
String s = new Owner().getMember(friend);
System.out.println(s);
}
}
Friend类如下所示。
public final class Friend {
private final Class as;
public Friend(final Object is) {
as = is.getClass();
}
public void is(final Class c) {
if (c == as)
return;
throw new ClassCastException(String.format("%s is not an expected friend.", as.getName()));
}
public void is(final Class... classes) {
for (final Class c : classes)
if (c == as)
return;
is((Class)null);
}
}
然而,问题是,它可能会被这样滥用:
public class Abuser {
public void doBadThings() {
Friend badFriend = new Friend(new Other());
String s = new Owner().getMember(badFriend);
System.out.println(s);
}
}
现在,Other类可能确实没有任何公共构造函数,因此不可能实现上面的Abuser代码。但是,如果您的类确实有一个公共构造函数,那么可能建议将Friend类复制为内部类。以Other2类为例:
public class Other2 {
private final Friend friend = new Friend();
public final class Friend {
private Friend() {}
public void check() {}
}
public void test() {
String s = new Owner2().getMember(friend);
System.out.println(s);
}
}
然后Owner2类是这样的:
public class Owner2 {
private final String member = "value";
public String getMember(final Other2.Friend friend) {
friend.check();
return member;
}
}
注意Other2。Friend类有一个私有构造函数,因此这是一种更安全的方式。