Perché non posso dichiarare metodi statici in un’interfaccia?

L’argomento dice la maggior parte di esso – qual è la ragione del fatto che i metodi statici non possono essere dichiarati in un’interfaccia?

public interface ITest { public static String test(); } 

Il codice sopra riportato mi dà il seguente errore (in Eclipse, almeno): “Modificatore non valido per il metodo di interfaccia ITest.test (); sono consentiti solo il pubblico e l’abstract”.

Ci sono alcuni problemi in gioco qui. Il primo è il problema di dichiarare un metodo statico senza definirlo. Questa è la differenza tra

 public interface Foo { public static int bar(); } 

e

 public interface Foo { public static int bar() { ... } } 

Il primo è imansible per le ragioni citate da Espo : non si sa quale class di implementazione sia la definizione corretta.

Java potrebbe consentire a quest’ultimo; e infatti, a partire da Java 8, lo fa!

Il motivo per cui non è ansible avere un metodo statico in un’interfaccia risiede nel modo in cui Java risolve i riferimenti statici. Java non si preoccuperà di cercare un’istanza di una class quando tenta di eseguire un metodo statico. Questo perché i metodi statici non dipendono dall’istanza e quindi possono essere eseguiti direttamente dal file di class. Dato che tutti i metodi in un’interfaccia sono astratti, la VM dovrebbe cercare una particolare implementazione dell’interfaccia per trovare il codice dietro il metodo statico in modo che possa essere eseguito. Questo contraddice quindi il modo in cui la risoluzione del metodo statico funziona e introdurrebbe un’incoerenza nella lingua.

Risponderò alla tua domanda con un esempio. Supponiamo di avere una class Math con un metodo statico add. Chiameresti questo metodo in questo modo:

 Math.add(2, 3); 

Se Math fosse un’interfaccia invece di una class, non avrebbe potuto avere funzioni definite. In quanto tale, dire qualcosa come Math.add (2, 3) non ha senso.

La ragione sta nel principio di progettazione, che java non consente l’ereditarietà multipla. Il problema con l’ereditarietà multipla può essere illustrato dal seguente esempio:

 public class A { public method x() {...} } public class B { public method x() {...} } public class C extends A, B { ... } 

Ora cosa succede se chiami Cx ()? Sarà eseguito Ax () o Bx ()? Ogni lingua con eredità multipla deve risolvere questo problema.

Le interfacce consentono in Java una sorta di ereditarietà multipla limitata. Per evitare il problema sopra, non è consentito avere metodi. Se guardiamo allo stesso problema con interfacce e metodi statici:

 public interface A { public static method x() {...} } public interface B { public static method x() {...} } public class C implements A, B { ... } 

Lo stesso problema qui, cosa succede se chiami Cx ()?

I metodi statici non sono metodi di istanza. Non c’è un contesto di istanza, quindi per implementarlo dall’interfaccia non ha molto senso.

Ora Java8 ci consente di definire anche i metodi statici nell’interfaccia.

 interface X { static void foo() { System.out.println("foo"); } } class Y implements X { //... } public class Z { public static void main(String[] args) { X.foo(); // Y.foo(); // won't compile because foo() is a Static Method of X and not Y } } 

Nota: i metodi in Interface sono ancora pubblici in modo predefinito per impostazione predefinita se non si utilizzano esplicitamente le parole chiave default / static per renderli metodi Defender e metodi Statici resp.

C’è una risposta molto bella e concisa alla tua domanda qui . (Mi ha colpito come un modo così semplice di spiegarlo che voglio collegarlo da qui.)

Sembra che il metodo statico nell’interfaccia possa essere supportato in Java 8 , beh, la mia soluzione è semplicemente definirli nella class interna.

 interface Foo { // ... class fn { public static void func1(...) { // ... } } } 

La stessa tecnica può essere utilizzata anche nelle annotazioni:

 public @interface Foo { String value(); class fn { public static String getValue(Object obj) { Foo foo = obj.getClass().getAnnotation(Foo.class); return foo == null ? null : foo.value(); } } } 

Si dovrebbe sempre accedere alla class interna sotto forma di Interface.fn... invece di Class.fn... , quindi, è ansible eliminare il problema ambiguo.

Un’interfaccia viene utilizzata per il polimorfismo, che si applica agli oggetti, non ai tipi. Pertanto (come già notato) non ha senso avere un membro di interfaccia statico.

Java 8 Aveva cambiato il mondo, puoi avere metodi statici nell’interfaccia ma ti costringe a fornire l’implementazione per quello.

 public interface StaticMethodInterface { public static int testStaticMethod() { return 0; } /** * Illegal combination of modifiers for the interface method * testStaticMethod; only one of abstract, default, or static permitted * * @param i * @return */ // public static abstract int testStaticMethod(float i); default int testNonStaticMethod() { return 1; } /** * Without implementation. * * @param i * @return */ int testNonStaticMethod(float i); 

}

Combinazione illegale di modificatori: statici e astratti

Se un membro di una class viene dichiarato statico, può essere utilizzato con il suo nome di class che è limitato a quella class, senza creare un object.

Se un membro di una class viene dichiarato come astratto, devi dichiarare la class come astratta e devi fornire l’implementazione del membro astratto nella sua class ereditata (Sottoclass).

È necessario fornire un’implementazione al membro astratto di una class in sottoclass in cui si modificherà il comportamento del metodo statico, anche dichiarato come astratto che è limitato alla class base, che non è corretto

Poiché i metodi statici non possono essere ereditati. Quindi non usare posizionandolo nell’interfaccia. Interface è fondamentalmente un contratto che tutti i suoi abbonati devono seguire. L’inserimento di un metodo statico nell’interfaccia costringerà gli abbonati a implementarlo. che ora diventa contraddittorio al fatto che i metodi statici non possono essere ereditati.

Forse un esempio di codice sarebbe d’aiuto, userò C #, ma dovresti essere in grado di seguirlo.

Fingiamo di avere un’interfaccia chiamata IPayable

 public interface IPayable { public Pay(double amount); } 

Ora abbiamo due classi concrete che implementano questa interfaccia:

 public class BusinessAccount : IPayable { public void Pay(double amount) { //Logic } } public class CustomerAccount : IPayable { public void Pay(double amount) { //Logic } } 

Ora, facciamo finta di avere una collezione di vari account, per fare questo useremo un elenco generico del tipo IPayable

 List accountsToPay = new List(); accountsToPay.add(new CustomerAccount()); accountsToPay.add(new BusinessAccount()); 

Ora, vogliamo pagare $ 50,00 a tutti quei conti:

 foreach (IPayable account in accountsToPay) { account.Pay(50.00); } 

Quindi ora vedi come le interfacce sono incredibilmente utili.

Sono utilizzati solo su oggetti istanziati. Non su classi statiche.

Se hai effettuato il pagamento statico, quando esegui il looping degli account IPayable in AccountToPay, non ci sarebbe modo di capire se è necessario chiamare il pagamento su BusinessAcount o CustomerAccount.