【问题标题】:Allowing instances of a particular class to be created by only one other class in Java?允许特定类的实例仅由 Java 中的另一个类创建?
【发布时间】:2013-11-29 14:04:55
【问题描述】:

假设我有两个类 A 和 B,我想让它使得 B 的实例只能在 A 和 B 本身中创建。我不希望任何其他类(包括 A 的子类)被允许创建 B 的实例。在 Java 中有没有办法做到这一点?

如果不清楚我要做什么,这里有一些代码:

public class A {
    B instance;
    public A(){
        // Still allows for subclasses to access B
        instance = B.getInstance((Object)this);
    }
}

这是我要限制其构造的类:

public class B {

    // If I make this public all classes can create it, but
    // if I make it private without any getter methods then
    // no other classes but itself can create it
    private B(){}

    // Problem with this is that subclasses of  A
    // can also create instances of B
    public static B getInstance(Object o){
        if(o instanceof A)
            return new B();
        else
            return null;
    } 
}

我已经尝试在 StackOverflow 上搜索和搜索可能的解决方案,但我发现最接近的方法是使用带有修改的 getInstance() 方法的 Singleton 设计模式,以确保只有具有特定类型的类才能访问B 类的实例。虽然这工作得很好,但它仍然使任何扩展 A 的子类都能够获取 B 的实例。有没有办法阻止这种情况发生,或者如果子类不能这样做,它会破坏子类化的全部意义它的超类能做什么?

【问题讨论】:

    标签: java singleton access-modifiers


    【解决方案1】:

    假设我有两个类 A 和 B,我想让它使得 B 的实例只能在 A 和 B 本身中创建。我不希望任何其他类(包括 A 的子类)被允许创建 B 的实例。

    你可以让 B 成为 A 类的私有内部类。

    【讨论】:

    • 是否有可能该类不是内部类,而是与他的主人在同一个包中,但仍然可以像内部类一样创建?
    【解决方案2】:

    虽然这工作得相当好,但它仍然启用任何子类 扩展 A 以获取 B 的实例。有没有办法阻止它 发生还是会破坏子类化的全部意义,如果 子类不能做它的超类能做的事?

    如果您不希望您的 A 类被子类化,您可以将 A 类设为 final,或者可以为 A 提供一个私有构造函数。尽管如前面的答案中所建议的那样,最好创建私有内部类。

    public final class A {
        B instance;
        public A(){
            // Still allows for subclasses to access B
            instance = B.getInstance((Object)this);
        }
    }
    

    【讨论】:

    • 虽然另一个答案稍微好一点,但对于我的特定应用程序,我实际上不需要首先创建 A 的子类,所以这很有用。另外,如果我想将冗长的私有内部类移动到它自己的单独源文件中以提高可读性,它可能会有所帮助。因此 +1。
    【解决方案3】:

    如果创建的类不是B,这个类会抛出异常

    class A {
    
        A() {
            new SecurityManager() {
                {
                    if (getClassContext()[1] != B.class) {
                        throw new IllegalStateException();
                    }
                }
            };
        }
    ...
    

    即使用反射也无法打破它

    【讨论】:

    • 这可行,尽管我认为条件必须是 getClassContext()[2] != B.class 因为 getClassContext()[1] 给你 A.class 和 getClassContext()[0] 给你是 SecurityManager 类。
    【解决方案4】:

    A 可以向B 呈现只有A 才能拥有的东西。例如

    public class A
    {
        public static class Pass
        {
            private Pass(){}
    

    只有A 可以创建A.Pass 对象。如果此类对象仅从A 传输到B,则没有其他人可以抓住它们并冒充A

    public class B
    {
        public static B getInstance(A.Pass token)
        {
            if(pass==null) 
                throw ...      
            else
                caller must be A
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-11-02
      • 1970-01-01
      • 2012-12-19
      • 1970-01-01
      • 1970-01-01
      • 2012-08-12
      • 2022-11-02
      相关资源
      最近更新 更多