27
votes

The javadoc for Void says:

The Void class is an uninstantiable placeholder class to hold a reference to the Class object representing the Java keyword void.

but the constructor is simply:

private Void() {}

and this code instantiates a Void:

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

So Void is not uninstantiable.

Would there have been a way to make Void truly uninstantiable?

3
Out of curiosity: do you need it? ;) I guess it is only a placeholder for the reflection API for methods returning void... Maybe of help only for proxies?fge
If you use reflections, you could do lot of things which are not possible by using API.kosa

3 Answers

31
votes

Rohit is quite right that throwing an exception is "good enough" for most use cases. However, it looks like it might be possible to bypass even that, using sun.misc.Unsafe:

public native Object allocateInstance(Class cls) throws InstantiationException

Allocate an instance but do not run any constructor. Initializes the class if it has not yet been.

(Note that I haven't actually tested that this works)

30
votes

Making your constructor private, and not having any other constructor that can be accessed by outside, makes a class un-instantiable.

However, you cannot avoid it from being accessed using Reflection API. Using reflection, you can do, what is not allowed normally.

But, if you really want your class to be uninstantiable, even through Reflection, you can throw an Unchecked Exception from the constructor.

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

In which case, when you create the instance using Constructor#newInstance() method, it will throw an InvocationTargetException, as quoted in comments by @Alex.

Here's the documentation of Constructor#newInstance() method, which declares a list of exception to be thrown, one of them is InvocationTargetException, and it says that: -

throws:
InvocationTargetException - if the underlying constructor throws an exception.

11
votes

The Reflection API breaks all kinds of "rules" like this, just like being able to modify final fields. There are many complaints about the fact that it allows you to break the hard and fast rules of Java, but that's how it is.

Without Reflection (or @StevenSchlansker's crazy Unsafe API posted below), it's not possible to instantiate. As long as Reflection is allowed, though, these workarounds will exist.

In Oracle's own Reflection tutorial, they list the benefits and drawbacks. It's up to you to decide which is greater.

Also, see this question: What is reflection and why is it useful?