Java 8 consente metodi di interfaccia statica
Con Java 8, le interfacce possono avere metodi statici. Possono anche avere metodi di istanza concreti, ma non campi di istanza.
Ci sono davvero due domande qui:
- Perché, ai vecchi tempi, le interfacce non potevano contenere metodi statici?
- Perché i metodi statici non possono essere ignorati?
Metodi statici nelle interfacce
Non vi era alcun motivo tecnico forte per cui le interfacce non avrebbero potuto avere metodi statici nelle versioni precedenti. Questo è riassunto piacevolmente dal poster di una domanda duplicata. I metodi di interfaccia statica sono stati inizialmente considerati come un piccolo cambio di lingua, quindi c'è stata una proposta ufficiale di aggiungerli in Java 7, ma è stato successivamente abbandonato a causa di complicazioni impreviste.
Infine, Java 8 ha introdotto metodi di interfaccia statica, nonché metodi di istanza di sostituzione con un'implementazione predefinita. Tuttavia non possono ancora avere campi di istanza. Queste funzioni fanno parte del supporto dell'espressione lambda e puoi leggere ulteriori informazioni su di esse nella parte H di JSR 335.
Sostituzione dei metodi statici
La risposta alla seconda domanda è un po 'più complicata.
I metodi statici sono risolvibili al momento della compilazione. Il dispacciamento dinamico ha senso, ad esempio, per i metodi, in cui il compilatore non è in grado di determinare il tipo concreto dell'oggetto e, quindi, non può risolvere il metodo da invocare. Ma invocare un metodo statico richiede una classe e poiché tale classe è conosciuta staticamente — al momento della compilazione — l'invio dinamico non è necessario.
Un piccolo background su come funzionano i metodi di istanza è necessario per capire cosa sta succedendo qui. Sono sicuro che l'implementazione effettiva è piuttosto diversa, ma lasciatemi spiegare la mia nozione di invio del metodo, quali modelli hanno osservato il comportamento in modo accurato.
Fai finta che ogni classe abbia una tabella hash che associ le firme dei metodi (nome e tipi di parametro) a un blocco di codice effettivo per implementare il metodo. Quando la macchina virtuale tenta di richiamare un metodo su un'istanza, interroga l'oggetto per la sua classe e cerca la firma richiesta nella tabella della classe. Se viene trovato un corpo del metodo, viene invocato. Altrimenti, si ottiene la classe genitore della classe e la ricerca viene ripetuta lì. Questo procede fino a quando non viene trovato il metodo o non ci sono più classi genitore, il che si traduce in a NoSuchMethodError
.
Se una superclasse e una sottoclasse hanno entrambe una voce nelle loro tabelle per la stessa firma del metodo, la versione della sottoclasse viene rilevata per prima e la versione della superclasse non viene mai utilizzata, questa è una "sostituzione".
Supponiamo ora di saltare l'istanza dell'oggetto e di iniziare con una sottoclasse. La risoluzione potrebbe procedere come sopra, offrendo una sorta di metodo statico "sostituibile". Tuttavia, la risoluzione può avvenire in fase di compilazione, poiché il compilatore parte da una classe nota, anziché attendere fino al runtime per interrogare un oggetto di un tipo non specificato per la sua classe. Non ha senso "sostituire" un metodo statico poiché si può sempre specificare la classe che contiene la versione desiderata.
Costruttori "interfacce"
Ecco un po 'più di materiale per indirizzare la modifica recente alla domanda.
Sembra che tu voglia imporre in modo efficace un metodo simile a quello di un costruttore per ogni implementazione di IXMLizable
. Dimentica di provare a imporre questo con un'interfaccia per un minuto e fai finta di avere alcune classi che soddisfano questo requisito. Come lo useresti?
class Foo implements IXMLizable<Foo> {
public static Foo newInstanceFromXML(Element e) { ... }
}
Foo obj = Foo.newInstanceFromXML(e);
Dal momento che è necessario nominare esplicitamente il tipo concreto Foo
quando si "costruisce" il nuovo oggetto, il compilatore può verificare che disponga effettivamente del metodo factory necessario. E se non lo fa, e allora? Se riesco a implementare un IXMLizable
che manca del "costruttore" e creo un'istanza e la passo al tuo codice, è una IXMLizable
con tutta l'interfaccia necessaria.
La costruzione fa parte dell'implementazione, non dell'interfaccia. Qualsiasi codice che funzioni correttamente con l'interfaccia non si preoccupa del costruttore. Qualsiasi codice che si preoccupi per il costruttore deve comunque conoscere il tipo concreto e l'interfaccia può essere ignorata.