27

javadocVoid说:

Void 类是一个不可实例化的占位符类,用于保存对表示 Java 关键字 void 的 Class 对象的引用。

但构造函数很简单:

private Void() {}

这段代码实例化了一个Void

Constructor<Void> c = Void.class.getDeclaredConstructor();
c.setAccessible(true);
Void v = c.newInstance(); // Hello sailor

所以Void不是不可实例化的。

有没有办法让Void真正不可实例化?

4

3 回答 3

31

Rohit 非常正确,对于大多数用例来说,抛出异常“已经足够好”了。但是,使用 sun.misc.Unsafe似乎甚至可以绕过它:

公共本机对象 allocateInstance(Class cls) 抛出 InstantiationException

分配一个实例但不运行任何构造函数。如果尚未初始化该类。

(请注意,我实际上并没有测试过它是否有效)

于 2012-12-27T19:53:11.363 回答
30

将您的构造函数设为私有,并且没有任何其他可以被外部访问的构造函数,使得类un-instantiable

但是,您无法避免使用Reflection API. 使用反射,您可以做通常不允许的事情。

但是,如果你真的希望你的类是不可实例化的,即使是通过反射,你也可以从构造函数throw中得到一个Unchecked Exception

private MyClass() {
    throw UnsupportedOperationException("Can't instantiate class");
}

在这种情况下,当您使用Constructor#newInstance()方法创建实例时,它会抛出一个InvocationTargetException,正如@Alex 的评论中所引用的那样。

这是方法的文档Constructor#newInstance(),它声明了要抛出的异常列表,其中之一是InvocationTargetException,它说:-

throws:
InvocationTargetException - 如果底层构造函数抛出异常。

于 2012-12-27T19:27:49.210 回答
11

Reflection API 像这样打破了各种“规则”,就像能够修改final字段一样。有很多抱怨说它允许你打破 Java 的硬性规则,但事实就是这样。

如果没有反射(或下面发布的@StevenSchlansker 的疯狂UnsafeAPI),就无法实例化。但是,只要允许反射,这些变通方法就会存在。

Oracle 自己的反射教程中,它们列出了优点和缺点。由您决定哪个更大。

另外,请参阅这个问题:什么是反射以及它为什么有用?

于 2012-12-27T19:25:08.763 回答