Domanda

L'argomento dice di più: qual è il motivo 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 non valido per il metodo di interfaccia ITest.test();sono consentiti solo pubblici e astratti".

È stato utile?

Soluzione

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 le ragioni che Espo menziona:non sai quale classe di implementazione è la definizione corretta.

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

Altri suggerimenti

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 funzionamento della risoluzione del metodo statico e introdurrebbe un'incoerenza nel linguaggio.

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

Math.add(2, 3);

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

Il motivo risiede nel principio di progettazione, ovvero che Java non consente l'ereditarietà multipla.Il problema dell’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 C.x()?Verrà eseguito A.x() o B.x()?Ogni linguaggio con ereditarietà multipla deve risolvere questo problema.

Le interfacce consentono in Java una sorta di eredità multipla ristretta.Per evitare il problema di cui sopra, non è consentito avere metodi.Se esaminiamo 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 { ... }

Stesso problema qui, cosa succede se chiami C.x()?

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

Ora Java8 ci consente di definire anche 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 pubblici astratti per impostazione predefinita se non utilizziamo esplicitamente le parole chiave default/static per renderli metodi predefiniti e metodi statici risp.

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

Sembra che il metodo statico nell'interfaccia potrebbe essere supportato Giava8, 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 di Interface.fn... invece di Class.fn..., quindi, puoi sbarazzarti del problema ambiguo.

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

Java 8 ha cambiato il mondo, puoi avere metodi statici nell'interfaccia ma ti costringe a fornirne l'implementazione.

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:statico e astratto

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

Se un membro di una classe viene dichiarato come astratto, è necessario dichiarare la classe come astratta e 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 modificherà il comportamento del metodo statico, dichiarato anche come astratto che è limitato alla classe base, il che non è corretto

Poiché i metodi statici non possono essere ereditati.Quindi è inutile inserirlo nell'interfaccia.L'interfaccia è fondamentalmente un contratto che tutti i suoi abbonati devono rispettare.L'inserimento di un metodo statico nell'interfaccia costringerà gli abbonati a implementarlo.il che ora diventa contraddittorio rispetto al fatto che i metodi statici non possono essere ereditati.

Con Giava8, le interfacce ora possono avere metodi statici.

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

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

Forse un esempio di codice potrebbe essere d'aiuto, userò C#, ma dovresti essere in grado di seguire.

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 conti, per fare questo utilizzeremo una lista generica 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 conti:

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

Quindi ora vedi come le interfacce sono incredibilmente utili.

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

Se avessi reso il pagamento statico, quando scorrevi gli IPayable in accountToPay non ci sarebbe modo di capire se dovrebbe chiamare il pagamento su BusinessAcount o CustomerAccount.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top