Void
的javadoc表示:
Void类是一个不可实例化的占位符类,用于保存对表示Java关键字Void的class对象的引用。
但是构造函数很简单:
private Void() {}
,下面的代码实例化了一个Void
:
Constructor<Void> c = Void.class.getDeclaredConstructor();
c.setAccessible(true);
Void v = c.newInstance(); // Hello sailor
所以Void
是而不是不可实例化的
是否有办法使Void
真正不可实例化?
Rohit非常正确,抛出异常"足够好";对于大多数用例。但是,使用sun.misc.Unsafe:
似乎可以绕过这个问题。public native Object allocateInstance(Class Class)抛出InstantiationException
分配一个实例但不运行任何实例构造函数。如果类尚未初始化,则初始化该类。
(注意,我还没有实际测试这是否有效)
将构造函数设置为私有,并且不允许任何其他可以被外部访问的构造函数,这会使类不可实例化。
但是,您不能避免使用Reflection API
访问它。使用反射,您可以做通常不允许的事情。
但是,如果你真的希望你的类是不可实例化的,即使通过反射,你可以从构造器中throw
Unchecked Exception。
private MyClass() {
throw UnsupportedOperationException("Can't instantiate class");
}
在这种情况下,当您使用Constructor#newInstance()
方法创建实例时,它将抛出InvocationTargetException
,如@Alex在注释中引用的。
下面是Constructor#newInstance()
方法的文档,它声明了要抛出的异常列表,其中一个是InvocationTargetException
,它说:-
抛出:
InvocationTargetException -如果底层构造函数抛出异常。
反射API打破了这样的各种"规则",就像能够修改final
字段一样。有很多人抱怨它允许你打破Java的硬性规则,但事实就是这样。
没有反射(或@StevenSchlansker的疯狂的Unsafe
API下面发布),它是不可能实例化的。但是,只要允许反射,这些变通方法就会存在。
在Oracle自己的反射教程中,他们列出了反射的优点和缺点。哪一个更大由你来决定。
还有,看看这个问题:什么是反射,它为什么有用?