关于java:私有类的公共构造函数

Public constructor of a private class

本问题已经有最佳答案,请猛点这里访问。

我是Java新手。 我想知道在私有类中使用公共构造函数是什么。 类中的私有类可以从同一个类初始化然后将私有类的构造函数公开的用途是什么?

1
2
3
4
5
6
7
public class MainActivity extends Activity {
     private class AcceptThread extends Thread {
        public AcceptThread() {

        }
    }
}


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

1
2
3
4
5
6
7
8
9
10
11
// 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。它首先检查类可见性,然后检查成员可见性。

默认修饰符是允许您直接从其他类调用构造函数的最严格的修饰符,因此package-private似乎是构造函数以及任何其他非私有方法的最合适的可见性。这样做的另一个好处是,如果将来更改类可见性,则不会意外地将构造函数或任何方法公开给公众。


你知道,我几乎每次创建私人内部课时都会问自己这个问题,但我总是认为公共构造函数可能有一些(可能是人为的)理由。所以@kapep的回答让我感到刺痛,并鼓励他们想办法在私人内部课堂上要求一个公共构造函数,但是我想的越多,实验就越多,我认为漏洞就越多。

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

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

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

    Exception in thread"main" java.lang.IllegalAccessException: Class A can not access a member of class contrived.B$C with modifiers"public"

  • 内部类扩展shenanigans :不要在家里尝试:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    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();
      }
    }

    起初似乎很有希望,但我对这一点并没有太过分。

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

那为什么这个技术合法,尽管没有用?可能是因为当没有提供其他构造函数时,编译器会自动插入一个无参数的公共构造函数。因此,语言不应该禁止这种结构。不过,更多的是人工制品而不是理由。