2012-12-27 3 views
23

Il javadoc for Void dice:Il vuoto è davvero non verificabile?

La classe Void è una classe segnaposto istanziabili di tenere un riferimento all'oggetto classe che rappresenta la parola chiave void Java.

ma il costruttore è semplicemente:

private Void() {} 

e questo codice crea un'istanza di un Void:

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

Quindi Void non è istanziabili.

Ci sarebbe stato un modo per rendere il Void davvero non convincente?

+2

curiosità: cosa avete bisogno? ;) Immagino che sia solo un segnaposto per la reflection API per i metodi _returning_ 'void' ... Forse di aiuto solo per i proxy? – fge

+2

Se si utilizzano i riflessi, è possibile eseguire molte cose che non sono possibili utilizzando l'API. – kosa

risposta

28

Effettuare la costruttore privato, e non avendo qualsiasi altro costruttore che può essere letta da fuori, fa una classe non-istanziabile.

Tuttavia, non è possibile evitare di accedervi utilizzando Reflection API. Usando il riflesso, puoi fare ciò che non è permesso normalmente.

Ma, se si vuole veramente la vostra classe di essere istanziabili, anche attraverso Riflessione, è possibile throw un incontrollato eccezione dal costruttore .

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

In questo caso, quando si crea l'istanza utilizzando Constructor#newInstance() metodo, genera un InvocationTargetException, come citato nei commenti da @alex.

Ecco la documentazione di Constructor#newInstance() metodo, che dichiara un elenco di eccezioni ad essere gettato, uno di loro è InvocationTargetException, e si dice che: -

tiri:
InvocationTargetException - se il costruttore sottostante getta un'eccezione.

+1

Non penso che l'eccezione debba essere deselezionata. Funzionerebbe anche se ne lanciasse uno controllato (forse 'java.lang.IllegalAccessException'?). – matts

+0

+1 Lanciare un'eccezione è il modo di farlo :) – Bohemian

+2

@matts Penso che qui sarebbe preferibile un'eccezione non controllata. Per uno, rende meno codice (nessuna clausola 'getta'), che è sempre una buona cosa. – Bohemian

10

L'API di Reflection interrompe tutti i tipi di "regole" come questa, proprio come poter modificare i campi final. Ci sono molte lamentele sul fatto che ti permette di rompere le regole rigide e veloci di Java, ma è così che è.

Senza Reflection (o l'API pazzo di StevenSchlansker Unsafe pubblicata di seguito), non è possibile creare un'istanza. Finché Reflection è consentito, tuttavia, questi metodi alternativi esisteranno.

In Oracle's own Reflection tutorial, elencano i vantaggi e gli svantaggi. Spetta a te decidere quale è maggiore.

Inoltre, questa domanda: What is reflection and why is it useful?

29

Rohit ha ragione nel dire che lanciare un'eccezione è "abbastanza buono" per la maggior parte dei casi d'uso.Tuttavia, sembra che potrebbe essere possibile bypass even that, using sun.misc.Unsafe:

pubblico oggetto nativo allocateInstance (Classe CLS) getta InstantiationException

assegnare un grado, ma non corrono alcun costruttore. Inizializza la classe se non è stata ancora eseguita.

(Si noti che non ho effettivamente testato che questo funziona)

+23

Wow. Questa è un'API spaventosa. – asteri