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


150

L'argomento dice di più: qual è la ragione per cui i metodi statici non possono essere dichiarati in un'interfaccia?

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

Il codice sopra mi dà il seguente errore (almeno in Eclipse): "Modificatore illegale per il metodo di interfaccia ITest.test (); sono ammessi solo pubblici e abstract".


2
Per favore, accetta la risposta di Espo, poiché è difettosa. Un'interfaccia ha un file di classe che potrebbe contenere l'implementazione di un metodo statico (se il progettista Java lo consentirebbe), quindi non ci sono problemi nel risolvere l'implementazione del metodo statico. Funziona esattamente come con altre classi statiche.
Mnementh,

I tipi di accordo con la risposta data da "Erickson" stackoverflow.com/questions/512877/...
Maverick

9
Questo sarà disponibile in Java 8 btw.
m0skit0,

1
@Vadorequest GIYF ma comunque, controlla qui
m0skit0

2
Collegamenti dalla documentazione ufficiale: tutorial su Java SE e specifiche del linguaggio Java 9.2
LoganMzz,

Risposte:


85

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 è impossibile per i motivi menzionati da Espo : non sai quale classe di implementazione sia la definizione corretta.

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


2
Sì, è logico non tecnico. Il motivo per cui mi piacerebbe è. che si può avere un metodo di "implementazione" statico in un'interfaccia che fa riferimento solo ad altri metodi di "interfaccia" nell'interfaccia che possono essere facilmente riutilizzati dalle classi di implementazione. Ma si può dichiarare una classe statica in un'interfaccia in modo da poter risiedere tali cose come MyInterface.Impl.doIt (MyInterface i, Object [] args) {...}
peterk,

9
Da Java 8, è possibile definire i staticmetodi in un interface. I metodi devono essere public.
Olivier Grégoire,

4
@ OlivierGrégoire ... e non sono ereditati, il che è fondamentale.
William F. Jameson,

1
Buona risposta, anche se ROFLMAO xD "approssimativamente equivalente" l'avrei messo più come "somiglia un po '".
Timo,

44

Il motivo per cui non è possibile 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 classe 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 classe. 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. Ciò quindi contraddice il modo in cui funziona la risoluzione del metodo statico e introdurrebbe un'incoerenza nel linguaggio.


3
Questa spiegazione non spiega il problema. Ogni interfaccia ha il proprio file di classe, potrebbe contenere il metodo statico. Quindi non sarebbe necessaria alcuna ricerca per una particolare implementazione.
Mnementh,

Non tutti i tipi di interfaccia in Java si trovano all'interno del proprio file, né dovrebbero essere secondo JLS. Inoltre, JLS non prevede che le classi debbano sempre essere archiviate all'interno di un file system, al contrario.
Vlad Gudim,

4
@Totophil: le interfacce non devono essere in un singolo file java, ma dopo la compilazione avrà un proprio file di classe. Questo è quello che ho scritto.
Mnementh,

18

Risponderò alla tua domanda con un esempio. Supponiamo di avere una classe di matematica con aggiunta di un metodo statico. Definiresti questo metodo in questo modo:

Math.add(2, 3);

Se la matematica fosse un'interfaccia anziché una classe, non potrebbe avere alcuna funzione definita. Pertanto, dire qualcosa come Math.add (2, 3) non ha senso.


11

Il motivo risiede nel principio di progettazione, secondo cui 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 { ... }

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

Le interfacce consentono in Java una sorta di eredità multipla limitata. Per evitare il problema sopra riportato, non sono autorizzati ad avere metodi. Se osserviamo lo 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 ()?


Qualche motivo per il downvote? Un commento esplicativo sarebbe carino.
Mnementh

non sono il downvoter, ma non è valido anche per i metodi non statici?
nawfal,

OK, qui ci sono due diverse possibilità. Un metodo potrebbe essere implementato o solo dichiarato. Ho capito che il metodo statico deve essere implementato. In questo senso, incontro il problema presentato nella mia risposta. Se non lo fai, ti imbatti nel problema descritto da Espo - e che non ho capito perché pensavo che il metodo statico sarebbe stato implementato. Inoltre, non puoi dichiarare un metodo astratto statico per questo motivo, provalo, il compilatore si lamenterà.
Mnementh,

Ok, dimentica la parte di implementazione. la domanda è: perché non possiamo dichiarare. sì, il compilatore si lamenterà e perché è questa la domanda. a cui non credo tu abbia risposto.
nawfal,

1
In che modo la situazione potrebbe essere peggiore che avere un'interfaccia Acontenente int x(int z);e l'interfaccia Bcontenere string x(int x);? Qual è il significato di x(3)nell'interfaccia C?
supercat

7

I metodi statici non sono metodi di istanza. Non esiste un contesto di istanza, quindi implementarlo dall'interfaccia ha poco senso.


5

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 nell'interfaccia sono ancora astratti pubblici per impostazione predefinita se non utilizziamo esplicitamente le parole chiave default / static per renderle rispettive Metodi predefiniti e metodi statici.


4

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


Questa non è una risposta alla domanda, nella migliore delle ipotesi dovrebbe essere un commento.
CubeJockey,

3

Sembra che il metodo statico nell'interfaccia potrebbe essere supportato in Java 8 , beh, la mia soluzione è semplicemente definirli nella classe 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 classe interna sotto forma Interface.fn...invece di Class.fn..., quindi, è possibile sbarazzarsi di problemi ambigui.


2

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 statica.


In alcuni contesti riflessivi sembra quasi avere senso però
Cruncher,

1

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

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);

}


0

Combinazione illegale di modificatori: statica e astratta

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

Se un membro di una classe viene dichiarato astratto, è necessario dichiarare la classe come astratta ed è necessario fornire l'implementazione del membro astratto nella sua classe ereditata (Sottoclasse).

È necessario fornire un'implementazione al membro astratto di una classe nella sottoclasse in cui si cambierà il comportamento del metodo statico, anche dichiarato astratto che è limitato alla classe base, che non è corretto


Come risponde alla domanda? L'OP ha chiesto dell'interfaccia mentre scrivevi sulla classe.
Lucky

0

Poiché i metodi statici non possono essere ereditati. Quindi non serve metterlo nell'interfaccia. L'interfaccia è fondamentalmente un contratto che tutti i suoi abbonati devono seguire. Inserire un metodo statico nell'interfaccia costringerà gli abbonati a implementarlo. che ora diventa contraddittorio al fatto che i metodi statici non possono essere ereditati.


i metodi statici sono sempre ereditati ma non possono essere sovrascritti.
Akki,

0

Con Java 8 , le interfacce possono ora avere metodi statici.

Ad esempio, Comparator ha un metodo statico naturalOrder ().

Anche il requisito secondo cui le interfacce non possono avere implementazioni è stato ridotto. Le interfacce possono ora dichiarare implementazioni di metodi "predefiniti", che sono come normali implementazioni con una sola eccezione: se erediti sia un'implementazione predefinita da un'interfaccia sia un'implementazione normale da una superclasse, l'implementazione della superclasse avrà sempre la priorità.


OH MIO DIO! Abbiamo un programmatore serio (e io, commentatore) che risponde (e io, commentando) a una domanda di 10 anni.
Mohamed Anees Il

Non ho notato la data :)
Ishara,

Haha! Nessun problema!
Mohamed Anees Il

-2

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

Facciamo finta 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 raccolta di vari account, per fare questo useremo un elenco generico del tipo IPayable

List<IPayable> accountsToPay = new List<IPayable>();
accountsToPay.add(new CustomerAccount());
accountsToPay.add(new BusinessAccount());

Ora, vogliamo pagare $ 50,00 a tutti questi account:

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 avessi reso pay statico, quando esegui il ciclo degli IPayable negli account To Pay non ci sarebbe modo di capire se dovrebbe chiamare pay su BusinessAcount o CustomerAccount.


Solo perché i metodi statici non hanno senso in QUESTO esempio, non significa che non abbiano senso in NESSUN esempio. Nel tuo esempio se l'interfaccia IPayable avesse un metodo statico "IncrementPayables" che tenesse traccia di quanti debiti sono stati aggiunti, questo sarebbe un vero caso d'uso. Certo, si potrebbe sempre usare una classe astratta, ma non è quello che hai affrontato. L'esempio in sé non pregiudica i metodi statici nelle interfacce.
Cruncher,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.