我希望能够在一个包中编写一个Java类,它可以访问另一个包中类的非公共方法,而不必使它成为另一个类的子类。这可能吗?
当前回答
没有使用关键字左右。
你可以使用反射等“作弊”,但我不建议“作弊”。
其他回答
没有使用关键字左右。
你可以使用反射等“作弊”,但我不建议“作弊”。
据我所知,这是不可能的。
也许,你可以给我们更多关于你的设计的细节。像这样的问题很可能是设计缺陷造成的。
只考虑
如果这些类如此密切相关,为什么它们在不同的包中? A是否访问B的私有成员,或者操作是否应该移动到类B并由A触发? 这是真正的调用还是事件处理更好?
下面是一个具有可重用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类有一个私有构造函数,因此这是一种更安全的方式。
Eirikma的回答简单而出色。我可能还要补充一点:与其使用一个公共可访问的方法getFriend()来获取一个不能使用的朋友,不如更进一步,不允许获取没有令牌的朋友:getFriend(Service.FriendToken)。这个FriendToken将是一个具有私有构造函数的内部公共类,因此只有Service可以实例化一个。
如果你想访问受保护的方法,你可以创建一个你想要使用的类的子类,它将你想要使用的方法公开为公共的(或者是更安全的命名空间内部的),并在你的类中有一个类的实例(将它用作代理)。
就私人方法而言(我认为)你运气不好。