我希望能够在一个包中编写一个Java类,它可以访问另一个包中类的非公共方法,而不必使它成为另一个类的子类。这可能吗?


当前回答

我认为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类有一个私有构造函数,因此这是一种更安全的方式。

如果你想访问受保护的方法,你可以创建一个你想要使用的类的子类,它将你想要使用的方法公开为公共的(或者是更安全的命名空间内部的),并在你的类中有一个类的实例(将它用作代理)。

就私人方法而言(我认为)你运气不好。

从Java 9开始,可以使用模块在许多情况下解决这个问题。

我认为,使用朋友访问器模式的方法太复杂了。我不得不面对同样的问题,我使用Java中来自c++的优秀的旧复制构造函数来解决:

public class ProtectedContainer {
    protected String iwantAccess;

    protected ProtectedContainer() {
        super();
        iwantAccess = "Default string";
    }

    protected ProtectedContainer(ProtectedContainer other) {
        super();
        this.iwantAccess = other.iwantAccess;
    }

    public int calcSquare(int x) {
        iwantAccess = "calculated square";
        return x * x;
    }
}

在你的应用程序中,你可以写以下代码:

public class MyApp {

    private static class ProtectedAccessor extends ProtectedContainer {

        protected ProtectedAccessor() {
            super();
        }

        protected PrivateAccessor(ProtectedContainer prot) {
            super(prot);
        }

        public String exposeProtected() {
            return iwantAccess;
        }
    }
}

这种方法的优点是只有您的应用程序可以访问受保护的数据。它并不完全是friend关键字的替代。但我认为当您编写自定义库并且需要访问受保护的数据时,它非常适合。

当你必须处理ProtectedContainer的实例时,你可以将ProtectedAccessor包裹在它周围,这样你就获得了访问权。

它还适用于受保护的方法。在API中定义它们。稍后在应用程序中编写一个私有包装器类,并将受保护的方法公开为公共方法。就是这样。

我认为c++中的友类就像Java中的内部类概念。使用内部类 实际上可以定义一个外围类和一个封闭类。封闭类具有对其封闭类的public和private成员的完全访问权。 请看下面的链接: http://docs.oracle.com/javase/tutorial/java/javaOO/nested.html