2012-12-27 17 views
23

Die javadoc for Void sagt:Ist Void wirklich uninstallierbar?

The Void-Klasse ist eine uninstantiable Platzhalter-Klasse ist ein Verweis auf das Klassenobjekt, die die Java-Schlüsselwort ungültig zu halten.

aber der Konstruktor ist einfach:

private Void() {} 

und dieser Code ein Void instanziiert:

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

So Void ist nicht uninstantiable.

Wäre es möglich gewesen, Void wirklich unsterblich zu machen?

+2

Aus Neugier: Sie brauchen es? ;) Ich denke, es ist nur ein Platzhalter für die Reflection API für Methoden _returning_ 'void' ... Vielleicht nur Hilfe für Proxies? – fge

+2

Wenn Sie Reflexionen verwenden, können Sie viele Dinge tun, die mit API nicht möglich sind. – kosa

Antwort

28

Erstellen der Konstruktor privat, und keinen anderen Konstruktor, die durch außerhalb zugegriffen werden kann, macht eine Klasse un-instantiable.

Sie können jedoch nicht verhindern, dass der Zugriff über Reflection API erfolgt. Mit Reflektion können Sie tun, was normalerweise nicht erlaubt ist.

Aber, wenn Sie wirklich wollen, Ihre Klasse uninstantiable, auch durch Reflexion können Sie throw eine Ungeprüfter Ausnahme vom Konstruktor zu sein.

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

In diesem Fall, wenn Sie die Instanz mit Constructor#newInstance() Methode zu erstellen, wird eine InvocationTargetException werfen, wie in den Kommentaren von @ Alex zitiert.

Hier ist die Dokumentation von Constructor#newInstance()-Methode, die eine Liste der Ausnahme erklärt geworfen werden, einer von ihnen InvocationTargetException ist, und sie sagt, dass: -

wirft:
InvocationTargetException -, wenn der Basiswert Konstruktor wirft eine Ausnahme.

+1

Ich glaube nicht, dass die Ausnahme deaktiviert werden müsste. Es würde auch funktionieren, wenn es einen überprüften (vielleicht 'java.lang.IllegalAccessException'?) Warf. – matts

+0

+1 Eine Ausnahme zu werfen ist der Weg, es zu tun :) – Bohemian

+2

@matts Ich denke, dass eine ungeprüfte Ausnahme hier bevorzugt wäre. Zum einen macht es weniger Code (keine "Throws" -Klausel), was immer eine gute Sache ist. – Bohemian

10

Die Reflection-API bricht alle Arten von "Regeln" so, als ob sie in der Lage wären, Felder final zu ändern. Es gibt viele Klagen über die Tatsache, dass es Ihnen erlaubt, die harten und schnellen Regeln von Java zu brechen, aber so ist es.

Ohne Reflection (oder @ StevenSchlanskers verrücktes Unsafe API unten veröffentlicht), ist es nicht möglich zu instanziieren. Solange Reflection erlaubt ist, werden diese Problemumgehungen existieren.

In Oracle's own Reflection tutorial, listet sie die Vor- und Nachteile auf. Es liegt an dir zu entscheiden, was größer ist.

Auch hierzu finden Sie diese Frage: What is reflection and why is it useful?

29

Rohit hat recht, dass das Auslösen einer Ausnahme für die meisten Anwendungsfälle "gut genug" ist.Allerdings sieht es aus wie es möglich sein könnte, zu bypass even that, using sun.misc.Unsafe:

öffentlichen nativen Objekt allocateInstance (Klasse cls) wirft InstantiationException

eine Instanz zuweisen, aber keinen Konstruktor ausgeführt. Initialisiert die Klasse, falls noch nicht geschehen.

(Beachten Sie, dass ich nicht wirklich getestet, dass dies funktioniert)

+23

Wow. Das ist eine beängstigende API. – asteri