27

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?

Roman C
  • 49,761
  • 33
  • 66
  • 176
Bohemian
  • 412,405
  • 93
  • 575
  • 722
  • 2
    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 Dec 27 '12 at 19:25
  • 3
    If you use reflections, you could do lot of things which are not possible by using API. – kosa Dec 27 '12 at 19:26

3 Answers3

31

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)

Community
  • 1
  • 1
Steven Schlansker
  • 37,580
  • 14
  • 81
  • 100
30

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.

Rohit Jain
  • 209,639
  • 45
  • 409
  • 525
  • 1
    I don't think the exception would need to be unchecked. It would also work if it threw a checked one (perhaps `java.lang.IllegalAccessException`?). – matts Dec 27 '12 at 19:32
  • 2
    @matts I think an unchecked exception would be preferred here. For one, it makes for less code (no `throws` clause), which is always a good thing. – Bohemian Dec 27 '12 at 19:33
  • @matts.. If you used `CheckedException`, and handled it in calling code, then moving further in that code may cause some problem because you might be using the instance you tried to create. In this case, if we don't want the class to be instantiated, it would be better to halt the execution with appropriate message, rather than handling it. – Rohit Jain Dec 27 '12 at 19:39
  • 9
    I don't think the choice of checked vs. unchecked really matters, in any case it will be wrapped in InvocationTargetException if the constructor is invoked via reflection. – Alex Dec 27 '12 at 19:52
  • Can't understand why so much of downvotes here, and that too without a single comment. – Rohit Jain Dec 27 '12 at 20:43
  • 1
    sun.misc.Unsafe allows an instance to be created without calling the constructor. Edit: didn't read the answer below this before I commented. – user253751 Jan 07 '14 at 01:42
  • 3
    You'd need to make the class final also, in order to prevent subclasses to be written - because once you have an instance of a subclass, you have an instance of a parent class. – Phil Jan 08 '14 at 05:11
  • @Phil (I know, years later, but...) Unless the subclass is nested inside the parent class the _`private`_ constructor is not visible, leading to a compilation error. Even when nested, if an exception is thrown by the parent's constructor then the subclass will also throw an exception upon instantiation; the exception can't even be caught (in the subclass constructor) because you can't surround a call to `super()` in a try-catch block. That said, making the class `final` better communicates intent and there's no reason for an un-instantiable class to be extensible. – Slaw Aug 17 '19 at 02:25
11

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?

Community
  • 1
  • 1
asteri
  • 11,402
  • 13
  • 60
  • 84