Void类是一个不可实例化的占位符类,用于保存对表示Java关键字void的Class对象的引用。
但构造函数只是:
private Void() {}
并且此代码实例化Void
:
Constructor<Void> c = Void.class.getDeclaredConstructor();
c.setAccessible(true);
Void v = c.newInstance(); // Hello sailor
所以Void
不不可实现。
是否有办法让Void
真正无法实现?
答案 0 :(得分:29)
Rohit非常正确,对于大多数用例而言,抛出异常“足够好”。但是,看起来bypass even that, using sun.misc.Unsafe:
似乎是可能的公共本机Object allocateInstance(Class cls)抛出 InstantiationException
分配实例但不运行任何实例 构造函数。如果该类尚未初始化,则对其进行初始化。
(请注意,我实际上没有测试过这是否有效)
答案 1 :(得分:28)
使您的构造函数成为私有,并且没有任何其他可以被外部访问的构造函数,从而使类不可实例化。
但是,您无法避免使用Reflection API
访问它。使用反射,你可以做,通常不允许的。
但是,如果您真的希望您的课程不可安装,即使通过 Reflection ,您也可以throw
未经检查的例外来自构造函数。
private MyClass() {
throw UnsupportedOperationException("Can't instantiate class");
}
在这种情况下,当您使用Constructor#newInstance()
方法创建实例时,它将抛出InvocationTargetException
,如@Alex的评论引用。
这是Constructor#newInstance()
方法的文档,它声明了要抛出的异常列表,其中一个是InvocationTargetException
,它说: -
throws:
InvocationTargetException - 如果是底层构造函数 抛出异常。
答案 2 :(得分:10)
Reflection API打破了这样的各种“规则”,就像能够修改final
字段一样。有很多人抱怨它可以让你打破Java的严格规则,但事实就是如此。
如果没有反射(或下面发布的@ StevenSchlansker的疯狂Unsafe
API),则无法实例化。但是,只要允许反射,这些变通方法就会存在。
在Oracle's own Reflection tutorial中,他们列出了利弊。由你决定哪个更大。