私有类的公共构造函数

2022-09-01 17:41:56

我是Java的新手。我想知道在私有类中使用公共构造函数是什么。类内的私有类可以从同一类初始化,那么将私有类的构造函数设置为公共有什么用呢?

public class MainActivity extends Activity {
     private class AcceptThread extends Thread {
        public AcceptThread() {

        }
    }
}

答案 1

对于具有私有类的公共或受保护的修饰符,似乎没有任何实际的用例。如果单个文件中有多个类(但不是嵌套类或本地类),则需要非私有构造函数来实例化私有类。

// X.java

public class X {
    private Y y = new Y();
}

class Y {
    Y () {
        // if this were private, X wouldn't be able to create an instance of Y
    }
}

实际上在这种情况下,默认或可见性足以创建实例。所有非私有修饰符都允许您从同一包中的其他类创建实例,但实际上具有相同的可见性。protected

  • 私有类对包外部的类不可见,因此方法在这里没有用处。public
  • 私有类不能由包外部的类扩展,因此也没有用处。protected
  • 即使使用反射,默认情况下也无法从其他包访问公共构造函数,并且会抛出 .它首先检查类可见性,然后检查成员可见性。IllegalAccessException

默认修饰符是限制性最强的修饰符,它允许您直接从其他类调用构造函数,因此包私有似乎是构造函数以及任何其他非私有方法最合适的可见性。这还具有一个优点,即如果将来更改类可见性,则不会意外地向公众公开构造函数或任何方法。


答案 2

你知道,几乎每次我做一个私有的内部类时,我都会问自己这个问题,但我一直认为公共构造函数可能有一些(可能是人为的)原因。因此,@kapep的答案让我感到刺痛,并鼓励我找到在私有内部类上要求公共构造函数的方法,但是我越是思考和实验,就越觉得漏洞被堵塞了。

可能的角度,所有这些都让我失望:

  • 序列化:当取消编组其超类不可序列化的对象时,超类需要一个可从子类访问的无 arg 构造函数。所以,这里应该总是足够的。protected

  • 反射工具:使用反射通过返回的实例获取内部类构造函数的代码。失败,因为首先检查类型可见性,正如@kapep指出的那样,尽管它留下了一条相当有趣的错误消息:

    线程 “main” java.lang.IllegalAccessException 中的异常:类 A 无法访问类人为的成员。带有修饰符“公共”的 B$C

  • 内部类扩展恶作剧:不要在家里尝试这个:

    package a;
    class Outer {
      private class Inner {
      }
    }
    
    package b;
    // compile error: Outer.Inner has private access in Outer
    class Extender extends a.Outer.Inner {
      Extender(a.Outer outer) {
        outer.super();
      }
    }
    

    起初似乎很有希望,但我并没有走得太远。


最后,我找不到一种方法来使私有内部类上的公共构造函数有用

那么,为什么这在技术上是合法的,尽管没有用处呢?可能是因为编译器在未提供其他构造函数时会自动插入 no-arg 公共构造函数。因此,语言不应该禁止这种结构。不过,与其说是原因,不如说是人工制品。