Perché non riesco a definire un metodo statico in un'interfaccia Java?


499

EDIT: A partire da Java 8, i metodi statici sono ora consentiti nelle interfacce.

Ecco l'esempio:

public interface IXMLizable<T>
{
  static T newInstanceFromXML(Element e);
  Element toXMLElement();
}

Naturalmente questo non funzionerà. Ma perchè no?

Uno dei possibili problemi potrebbe essere, cosa succede quando chiami:

IXMLizable.newInstanceFromXML(e);

In questo caso, penso che dovrebbe semplicemente chiamare un metodo vuoto (es. {}). Tutte le sottoclassi sarebbero costrette a implementare il metodo statico, quindi andrebbero tutti bene quando si chiama il metodo statico. Allora perché non è possibile?

EDIT: immagino che sto cercando una risposta più profonda di "perché è così che è Java".

C'è un motivo tecnologico particolare per cui i metodi statici non possono essere sovrascritti? Cioè, perché i progettisti di Java hanno deciso di rendere i metodi di istanza irreversibili ma non metodi statici?

EDIT: Il problema con il mio design è che sto cercando di utilizzare le interfacce per applicare una convenzione di codifica.

Cioè, l'obiettivo dell'interfaccia è duplice:

  1. Voglio che l'interfaccia IXMLizable mi permetta di convertire le classi che la implementano in elementi XML (usando il polimorfismo, funziona bene).

  2. Se qualcuno vuole creare una nuova istanza di una classe che implementa l'interfaccia IXMLizable, saprà sempre che ci sarà un nuovo costruttore staticoInstanceFromXML (Element e).

C'è un altro modo per garantire questo, oltre a inserire un commento nell'interfaccia?


4
Non è necessario ingombrare le definizioni dei metodi (e dei campi) con le interfacce pubbliche, tra l'altro.
Tom Hawtin - tackline

Hmm, sembra essere un duplicato di stackoverflow.com/questions/21817/… . Non l'avevo mai visto prima.
Michael Myers

1
Potresti fornire un po 'di codice come vorresti utilizzare i metodi di interfaccia statica?
Pavel Feldman,

43
Ciò sarà possibile in Java 8: docs.oracle.com/javase/tutorial/java/IandI/…
dakshang

1
@dakshang Sì, ma non fa ciò che l'OP vuole.
user253751

Risposte:


518

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:

  1. Perché, ai vecchi tempi, le interfacce non potevano contenere metodi statici?
  2. 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 Fooquando 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 IXMLizableche manca del "costruttore" e creo un'istanza e la passo al tuo codice, è una IXMLizablecon 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.



12
La ragione per # 1 potrebbe essere ereditarietà multipla? Dato che possiamo ereditare da più interfacce, se due interfacce contenessero la stessa firma del metodo statico e quindi una classe le implementasse entrambe e chiamasse quel metodo, allora le cose potrebbero complicarsi in un modo che i creatori del linguaggio Java volevano evitare impedendo l'ereditarietà di più classi in il primo posto. Lo stesso argomento potrebbe ovviamente essere fatto per l'interfaccia che non consente alcuna definizione del metodo in essi.
shrini1000

1
@ shrini1000 - No, i metodi statici vengono risolti al momento della compilazione. L'ambiguità può essere gestita nello stesso modo in cui viene gestita con costanti: con un errore del compilatore. Tuttavia, la proposta nell'ambito del Progetto Coin è stata respinta, citando alcune difficoltà impreviste. Non sono sicuro di cosa fossero, ma non credo che fosse su questa linea.
Erickson,

1
@ tgm1024 Sì, la sezione "Interfacce" del costruttore spiega perché non ha senso tentare di invocare un comportamento polimorfico attraverso un tipo noto al momento della compilazione. Come invocheresti RESET()una lezione? Scriveresti SomeClass.RESET(). Quindi non hai bisogno di un'interfaccia per descrivere quell'API; è statico. Le interfacce vengono utilizzate quando non si conosce il tipo concreto al momento della compilazione. Non è mai il caso di un metodo statico.
Erickson,

2
"La costruzione fa parte dell'implementazione, non dell'interfaccia. Qualsiasi codice che funzioni correttamente con l'interfaccia non si preoccupa del costruttore." - Questo chiaramente non è vero. In altre lingue (ad esempio Swift), posso creare nuove istanze Tsenza sapere Tstaticamente, perché prometto in un'interfaccia che un certo costruttore (o metodo statico) esisterà in fase di esecuzione. Il fatto che la generazione sia impossibile da specificare in Java non significa che non sia una cosa significativa da fare.
Raffaello

48

Questo è già stato chiesto e risposto, qui

Per duplicare la mia risposta:

Non ha mai senso dichiarare un metodo statico in un'interfaccia. Non possono essere eseguiti dalla normale chiamata MyInterface.staticMethod (). Se li chiami specificando la classe di implementazione MyImplementor.staticMethod (), devi conoscere la classe effettiva, quindi è irrilevante se l'interfaccia la contiene o meno.

Ancora più importante, i metodi statici non vengono mai ignorati e se si tenta di eseguire:

MyInterface var = new MyImplementingClass();
var.staticMethod();

le regole statiche dicono che il metodo definito nel tipo dichiarato di var deve essere eseguito. Dal momento che questa è un'interfaccia, questo è impossibile.

Il motivo per cui non è possibile eseguire "result = MyInterface.staticMethod ()" è che dovrebbe eseguire la versione del metodo definito in MyInterface. Ma non può esserci una versione definita in MyInterface, perché è un'interfaccia. Non ha codice per definizione.

Mentre si può dire che ciò equivale a "perché Java lo fa in questo modo", in realtà la decisione è una conseguenza logica di altre decisioni di progettazione, anche per un'ottima ragione.


14
Se si utilizza <T estende MyInterface> come parametro di tipo generico, sarebbe bello garantire tramite l'interfaccia che T può .doSomething ().
Chris Betti,

4
Pur comprendendo gli argomenti, sono d'accordo con @Chris_Betti (anche per i tipi non generici): sarebbe bello che la struttura del codice assicuri che alcune classi implementino una specifica API statica. Forse è possibile usare un concetto diverso ...
Juh_

@Juh_, ..... o una nuova parola chiave, se assolutamente necessario. Credo che staticsia un termine scadente nelle lingue ed è stato allungato troppo. Quindi averlo da solo è già impreciso. Vedi il mio esempio sopra stackoverflow.com/questions/512877/… {shrug}.

3
Questo sembra falso: "Non ha mai senso dichiarare un metodo statico in un'interfaccia". Se ho una raccolta di classi che, senza essere istanziato, potrebbe offrirmi alcune informazioni ma avrei bisogno di un'interfaccia comune per inserire queste informazioni statiche a livello di classe (cioè un'interfaccia con un metodo statico scavalcabile), allora è un uso valido . Pensa a reflection ++, dove puoi acquisire meta-informazioni sulle proprietà della classe senza andare in giro con attributi, riflessioni, ecc.
Jason

1
"Non ha mai senso dichiarare un metodo statico in un'interfaccia." Questo non è vero: immagina che il tuo sistema abbia un risolutore di classi predefinito. Se rileva l'implementazione del metodo ContainerInjectionInterce :: create (Container $ container), ad esempio creerà l'oggetto con questa funzione.
user3790897,

37

Normalmente questo viene fatto usando un modello Factory

public interface IXMLizableFactory<T extends IXMLizable> {
  public T newInstanceFromXML(Element e);
}

public interface IXMLizable {
  public Element toXMLElement();
}

7
+1 un modello di fabbrica sembra la soluzione al problema. (anche se non alla domanda)
pvgoddijn,

Qualcuno può dirmi qual è il significato di mettere <T extends IXMLizable> qui. Sono nuovo di Java. Cosa fa?
Nuwan Harshakumara Piyarathna,

1
@NuwanHarshakumaraPiyarathna T deve essere una classe che estende IXMLizable. Guarda i generici Java per una migliore comprensione di ciò che questo significa
Adriano,

37

Con l'avvento di Java 8 è ora possibile scrivere metodi predefiniti e statici nell'interfaccia. docs.oracle/staticMethod

Per esempio:

public interface Arithmetic {

    public int add(int a, int b);

    public static int multiply(int a, int b) {
        return a * b;
    }
}
public class ArithmaticImplementation implements Arithmetic {

    @Override
    public int add(int a, int b) {
        return a + b;
    }

    public static void main(String[] args) {
        int result = Arithmetic.multiply(2, 3);
        System.out.println(result);
    }
}

Risultato : 6

SUGGERIMENTO: la chiamata di un metodo di interfaccia statica non richiede l'implementazione di alcuna classe. Sicuramente ciò accade perché le stesse regole per i metodi statici nelle superclassi si applicano ai metodi statici sulle interfacce.


Questo è un perfetto esempio di questa domanda.

21

Perché i metodi statici non possono essere sovrascritti nelle sottoclassi e quindi non possono essere astratti. E tutti i metodi in un'interfaccia sono, di fatto , astratti.


2
È sempre possibile forzare ogni tipo per implementare qualsiasi metodo di interfaccia statica. Macchine da scrivere, qualcuno?
MichaelGG,

16
Esci da te stesso e rispondi alla domanda: perché un metodo statico non può essere ignorato? Se si potessero ignorare i metodi statici, come sarebbe? Cosa potresti fare con loro? Questa risposta è sostanzialmente "Non puoi perché non puoi".
Erickson,

10

Perché non riesco a definire un metodo statico in un'interfaccia Java?

In realtà è possibile in Java 8.

Secondo il documento Java :

Un metodo statico è un metodo associato alla classe in cui è definito anziché a qualsiasi oggetto. Ogni istanza della classe condivide i suoi metodi statici

In Java 8 un'interfaccia può avere metodi predefiniti e metodi statici . Questo ci facilita l'organizzazione dei metodi di supporto nelle nostre librerie. Possiamo mantenere metodi statici specifici per un'interfaccia nella stessa interfaccia piuttosto che in una classe separata.

Esempio di metodo predefinito:

list.sort(ordering);

invece di

Collections.sort(list, ordering);

Esempio di metodo statico (dal documento stesso):

public interface TimeClient {
    // ...
    static public ZoneId getZoneId (String zoneString) {
        try {
            return ZoneId.of(zoneString);
        } catch (DateTimeException e) {
            System.err.println("Invalid time zone: " + zoneString +
                "; using default time zone instead.");
            return ZoneId.systemDefault();
        }
    }

    default public ZonedDateTime getZonedDateTime(String zoneString) {
        return ZonedDateTime.of(getLocalDateTime(), getZoneId(zoneString));
    }    
}

6

Le interfacce riguardano il polimorfismo che è intrinsecamente legato alle istanze dell'oggetto, non alle classi. Pertanto statico non ha senso nel contesto di un'interfaccia.


Logica chiara e concisa. Ben messo.
Oke Uwechue,

6

Innanzitutto, tutte le decisioni relative alla lingua sono decisioni prese dai creatori della lingua. Non c'è nulla nel mondo dell'ingegneria del software o della definizione del linguaggio o della scrittura di compilatore / interprete che affermi che un metodo statico non può far parte di un'interfaccia. Ho creato un paio di lingue e scritto compilatori per loro - è tutto semplicemente seduto e definendo una semantica significativa. Direi che la semantica di un metodo statico in un'interfaccia è notevolmente chiara, anche se il compilatore deve rinviare la risoluzione del metodo al runtime.

In secondo luogo, il fatto che utilizziamo metodi statici significa che esiste un motivo valido per avere un modello di interfaccia che include metodi statici: non posso parlare per nessuno di voi, ma uso metodi statici su base regolare.

La risposta probabilmente più corretta è che non era percepita la necessità, al momento della definizione della lingua, di metodi statici nelle interfacce. Java è cresciuto molto nel corso degli anni e questo è apparentemente un oggetto che ha suscitato interesse. Il fatto che sia stato esaminato Java 7 indica che è aumentato a un livello di interesse che potrebbe comportare un cambio di lingua. Io, per esempio, sarò felice quando non dovrò più istanziare un oggetto solo così posso chiamare il mio metodo getter non statico per accedere a una variabile statica in un'istanza di sottoclasse ...


5

I metodi statici non sono virtuali come i metodi di istanza, quindi suppongo che i progettisti Java abbiano deciso di non volerli nelle interfacce.

Ma puoi inserire classi contenenti metodi statici all'interno delle interfacce. Potresti provarlo!

public interface Test {
    static class Inner {
        public static Object get() {
            return 0;
        }
    }
}

5
  • "C'è un motivo particolare per cui i metodi statici non possono essere ignorati".

Consentitemi di riformulare questa domanda compilando le definizioni.

  • "C'è un motivo particolare per cui i metodi risolti in fase di compilazione non possono essere risolti in fase di esecuzione."

Oppure, per aggiungere più completamente, se voglio chiamare un metodo senza un'istanza, ma conoscendo la classe, come posso risolverlo in base all'istanza che non ho.


3

Diverse risposte hanno discusso dei problemi con il concetto di metodi statici scavalcabili. Tuttavia a volte ti imbatti in uno schema in cui sembra che sia proprio quello che vuoi usare.

Ad esempio, lavoro con un livello relazionale oggetto che ha oggetti valore, ma ha anche comandi per manipolare gli oggetti valore. Per vari motivi, ogni classe di oggetti valore deve definire alcuni metodi statici che consentono al framework di trovare l'istanza del comando. Ad esempio, per creare una persona faresti:

cmd = createCmd(Person.getCreateCmdId());
Person p = cmd.execute();

e per caricare una persona per ID che faresti

cmd = createCmd(Person.getGetCmdId());
cmd.set(ID, id);
Person p = cmd.execute();

Questo è abbastanza conveniente, tuttavia ha i suoi problemi; in particolare, l'esistenza di metodi statici non può essere imposta nell'interfaccia. Un metodo statico ignorabile nell'interfaccia sarebbe esattamente ciò di cui avremmo bisogno, se solo potesse funzionare in qualche modo.

Gli EJB risolvono questo problema avendo un'interfaccia Home; ogni oggetto sa come trovare la propria Home e la Home contiene i metodi "statici". In questo modo i metodi "statici" possono essere sovrascritti, se necessario, e non ingombrare la normale (si chiama "Remote") interfaccia con metodi che non si applicano a un'istanza del bean. Basta fare in modo che l'interfaccia normale specifichi un metodo "getHome ()". Restituisce un'istanza dell'oggetto Home (che potrebbe essere un singleton, suppongo) e il chiamante può eseguire operazioni che incidono su tutti gli oggetti Person.


3

Commentando EDIT: As of Java 8, static methods are now allowed in interfaces.

È corretto, i metodi statici poiché Java 8 sono consentiti nelle interfacce, ma il tuo esempio continua a non funzionare. Non puoi semplicemente definire un metodo statico: devi implementarlo o otterrai un errore di compilazione.


2

Bene, senza generici, le interfacce statiche sono inutili perché tutte le chiamate ai metodi statici vengono risolte al momento della compilazione. Quindi, non serve a loro.

Con i generici, hanno un uso - con o senza un'implementazione predefinita. Ovviamente ci sarebbe bisogno di essere prioritari e così via. Tuttavia, la mia ipotesi è che tale utilizzo non fosse molto OO (come le altre risposte sottolineano in modo ottuso) e quindi non è stato considerato degno dello sforzo che avrebbero richiesto per implementare utilmente.


1
Che cosa hanno a che fare i generici con questo? Un metodo statico su un'interfaccia sarebbe ancora non eseguibile.
DJClayworth,

Innanzitutto, sarebbe una decisione di attuazione. Ma suppongo che non voglia chiamare metodi statici su un'interfaccia (potrebbe semplicemente usare una classe). Ma invece vuole avere qualcosa di simile a una typeclass o quantomeno ai parametri di tipo. In effetti, la sua ultima modifica lo mostra ancora più chiaramente.
MichaelGG,

2
Why can't I define a static method in a Java interface?

Tutti i metodi in un'interfaccia sono esplicitamente astratti e quindi non è possibile definirli come statici perché i metodi statici non possono essere astratti.


1

Un'interfaccia non può mai essere referenziata staticamente, ad es ISomething.member. Un'interfaccia è sempre riferita tramite una variabile che fa riferimento a un'istanza di una sottoclasse dell'interfaccia. Pertanto, un riferimento all'interfaccia non può mai sapere a quale sottoclasse si riferisce senza un'istanza della sua sottoclasse.

Quindi l'approssimazione più vicina a un metodo statico in un'interfaccia sarebbe un metodo non statico che ignora "questo", cioè non accede a nessun membro non statico dell'istanza. All'astrazione di basso livello, ogni metodo non statico (dopo la ricerca in qualsiasi vtable) è in realtà solo una funzione con scopo di classe che prende "questo" come un parametro formale implicito. Vedi l'oggetto singleton di Scala e l'interoperabilità con Java come prova di quel concetto. E quindi ogni metodo statico è una funzione con ambito di classe che non accetta un parametro "this". Quindi normalmente un metodo statico può essere chiamato staticamente, ma come precedentemente affermato, un'interfaccia non ha implementazione (è astratta).

Pertanto, per ottenere l'approssimazione più vicina a un metodo statico in un'interfaccia, è utilizzare un metodo non statico, quindi non accedere a nessuno dei membri dell'istanza non statica. Non ci sarebbero altri vantaggi in termini di prestazioni in nessun altro modo, perché non esiste un modo per collegare staticamente (in fase di compilazione) a ISomething.member(). L'unico vantaggio che vedo di un metodo statico in un'interfaccia è che non inserirà (cioè ignorerà) un "questo" implicito e quindi non consentirebbe l'accesso a nessuno dei membri di istanza non statici. Ciò dichiarerebbe implicitamente che la funzione che non accede a "questo", è immutata e nemmeno di sola lettura rispetto alla sua classe contenente. Ma una dichiarazione di "statico" in un'interfaccia ISomethingconfonderebbe anche le persone che hanno tentato di accederviISomething.member()che causerebbe un errore del compilatore. Suppongo che se l'errore del compilatore fosse sufficientemente esplicativo, sarebbe meglio che cercare di educare le persone sull'uso di un metodo non statico per ottenere ciò che vogliono (apparentemente principalmente metodi di fabbrica), come stiamo facendo qui (ed è stato ripetuto per 3 Domande e risposte su questo sito), quindi è ovviamente un problema non intuitivo per molte persone. Ho dovuto pensarci per un po 'per ottenere la comprensione corretta.

Il modo per ottenere un campo statico mutevole in un'interfaccia è utilizzare metodi getter e setter non statici in un'interfaccia, per accedere a quel campo statico che nella sottoclasse. Sidenote, statica apparentemente immutabile può essere dichiarata in un'interfaccia Java con static final.


0

Le interfacce forniscono semplicemente un elenco di cose che una classe fornirà, non un'implementazione effettiva di quelle cose, che è l'oggetto statico.

Se si desidera la statica, utilizzare una classe astratta ed ereditarla, altrimenti rimuovere la statica.

Spero che aiuti!


2
Bene, in teoria, potresti definire un'interfaccia per includere un comportamento statico, cioè "le implementazioni di questa interfaccia avranno un metodo statico foo () con questa firma", e lasceranno l'implementazione alla classe specifica. Ho riscontrato situazioni in cui questo comportamento sarebbe utile.
Rob,

0

Non è possibile definire metodi statici in un'interfaccia perché i metodi statici appartengono a una classe non a un'istanza di classe e le interfacce non sono Classi. Leggi di più qui.

Tuttavia, se vuoi puoi farlo:

public class A {
  public static void methodX() {
  }
}

public class B extends A {
  public static void methodX() {
  }
}

In questo caso, hai due classi con 2 metodi statici distinti chiamati methodX ().


0

Supponiamo che tu possa farlo; considera questo esempio:

interface Iface {
  public static void thisIsTheMethod();
}

class A implements Iface {

  public static void thisIsTheMethod(){
    system.out.print("I'm class A");
  }

}

class B extends Class A {

  public static void thisIsTheMethod(){
    System.out.print("I'm class B");
  } 
}

SomeClass {

  void doStuff(Iface face) {
    IFace.thisIsTheMethod();
    // now what would/could/should happen here.
  }

}

1
Stampa "Sono di classe A". Tuttavia, se hai digitato A.thisIsTheMethod(), verrebbe stampato "I'm class B".
cdmckay,

ma oyr chiamando i metodi sull'interfaccia come faresti tu (o il compilatore) quale metodo dovrebbe essere chiamato? (ricorda che possono esserci più classi che implementano drasticamente Iface
pvgoddijn,

scusate, volevo dire: tuttavia, se lo digitate B.thisIsTheMethod(), si stampa "Sono di classe B".
cdmckay,

ho detto IFace.thisIsTHeMethod apposta perché qui sta il problema. non sarebbe possibile chiamarlo sull'interfaccia senza un comportamento indefinito (anche se è dichiarato su di esso)
pvgoddijn,

0

Qualcosa che potrebbe essere implementato è un'interfaccia statica (invece del metodo statico in un'interfaccia). Tutte le classi che implementano una data interfaccia statica dovrebbero implementare i metodi statici corrispondenti. È possibile ottenere un'interfaccia statica SI da qualsiasi classe Class utilizzando

SI si = clazz.getStatic(SI.class); // null if clazz doesn't implement SI
// alternatively if the class is known at compile time
SI si = Someclass.static.SI; // either compiler errror or not null

allora puoi chiamare si.method(params). Ciò sarebbe utile (ad esempio per il modello di progettazione di fabbrica) perché è possibile ottenere (o controllare l'implementazione di) metodi di implementazione statica SI da una classe sconosciuta in fase di compilazione! È necessario un dispacciamento dinamico ed è possibile sovrascrivere i metodi statici (se non definitivi) di una classe estendendolo (quando viene chiamato attraverso l'interfaccia statica). Ovviamente, questi metodi possono accedere solo alle variabili statiche della loro classe.


0

Mentre mi rendo conto che Java 8 risolve questo problema, ho pensato di entrare in uno scenario su cui sto attualmente lavorando (bloccato nell'uso di Java 7) in cui essere in grado di specificare metodi statici in un'interfaccia sarebbe utile.

Ho diverse definizioni enum in cui ho definito i campi "id" e "displayName" insieme a metodi di supporto che valutano i valori per vari motivi. L'implementazione di un'interfaccia mi consente di garantire che siano presenti i metodi getter ma non i metodi helper statici. Essendo un enum, non c'è davvero un modo pulito per scaricare i metodi helper in una classe astratta ereditata o qualcosa del genere, quindi i metodi devono essere definiti nell'enum stesso. Anche perché è un enum, non saresti mai in grado di passarlo effettivamente come oggetto istanziato e trattarlo come il tipo di interfaccia, ma essere in grado di richiedere l'esistenza dei metodi di supporto statici attraverso un'interfaccia è ciò che mi piace di essendo supportato in Java 8.

Ecco il codice che illustra il mio punto.

Definizione dell'interfaccia:

public interface IGenericEnum <T extends Enum<T>> {
    String getId();
    String getDisplayName();
    //If I was using Java 8 static helper methods would go here
}

Esempio di una definizione enum:

public enum ExecutionModeType implements IGenericEnum<ExecutionModeType> {
    STANDARD ("Standard", "Standard Mode"),
    DEBUG ("Debug", "Debug Mode");

    String id;
    String displayName;

    //Getter methods
    public String getId() {
        return id;
    }

    public String getDisplayName() {
        return displayName;
    }

    //Constructor
    private ExecutionModeType(String id, String displayName) {
        this.id = id;
        this.displayName = displayName;
    }

    //Helper methods - not enforced by Interface
    public static boolean isValidId(String id) {
        return GenericEnumUtility.isValidId(ExecutionModeType.class, id);
    }

    public static String printIdOptions(String delimiter){
        return GenericEnumUtility.printIdOptions(ExecutionModeType.class, delimiter);
    }

    public static String[] getIdArray(){
        return GenericEnumUtility.getIdArray(ExecutionModeType.class);
    }

    public static ExecutionModeType getById(String id) throws NoSuchObjectException {
        return GenericEnumUtility.getById(ExecutionModeType.class, id);
    }
}

Definizione dell'utilità enum generica:

public class GenericEnumUtility {
    public static <T extends Enum<T> & IGenericEnum<T>> boolean isValidId(Class<T> enumType, String id) {       
        for(IGenericEnum<T> enumOption : enumType.getEnumConstants()) {
            if(enumOption.getId().equals(id)) {
                return true;
            }
        }

        return false;
    }

    public static <T extends Enum<T> & IGenericEnum<T>> String printIdOptions(Class<T> enumType, String delimiter){
        String ret = "";
        delimiter = delimiter == null ? " " : delimiter;

        int i = 0;
        for(IGenericEnum<T> enumOption : enumType.getEnumConstants()) {
            if(i == 0) {
                ret = enumOption.getId();
            } else {
                ret += delimiter + enumOption.getId();
            }           
            i++;
        }

        return ret;
    }

    public static <T extends Enum<T> & IGenericEnum<T>> String[] getIdArray(Class<T> enumType){
        List<String> idValues = new ArrayList<String>();

        for(IGenericEnum<T> enumOption : enumType.getEnumConstants()) {
            idValues.add(enumOption.getId());
        }

        return idValues.toArray(new String[idValues.size()]);
    }

    @SuppressWarnings("unchecked")
    public static <T extends Enum<T> & IGenericEnum<T>> T getById(Class<T> enumType, String id) throws NoSuchObjectException {
        id = id == null ? "" : id;
        for(IGenericEnum<T> enumOption : enumType.getEnumConstants()) {
            if(id.equals(enumOption.getId())) {
                return (T)enumOption;
            }
        }

        throw new NoSuchObjectException(String.format("ERROR: \"%s\" is not a valid ID. Valid IDs are: %s.", id, printIdOptions(enumType, " , ")));
    }
}

0

Supponiamo che nelle interfacce siano consentiti metodi statici: * Costringerebbero tutte le classi di implementazione a dichiarare quel metodo. * Le interfacce verrebbero normalmente utilizzate attraverso gli oggetti, quindi gli unici metodi efficaci su questi sarebbero quelli non statici. * Qualsiasi classe che conosce una particolare interfaccia potrebbe invocare i suoi metodi statici. Quindi il metodo statico di una classe di implementazione sarebbe chiamato sotto, ma la classe di invocatore non sa quale. Come saperlo? Non ha un'istanza per indovinarlo!

Si pensava che le interfacce fossero usate quando si lavora con oggetti. In questo modo, un oggetto viene istanziato da una classe particolare, quindi quest'ultima questione è risolta. La classe che invoca non ha bisogno di sapere quale classe particolare è perché l'istanza può essere fatta da una terza classe. Quindi la classe che invoca conosce solo l'interfaccia.

Se vogliamo che questo sia esteso ai metodi statici, dovremmo avere la possibilità di specificare prima una classe di implementazione, quindi passare un riferimento alla classe che invoca. Questo potrebbe usare la classe attraverso i metodi statici nell'interfaccia. Ma qual è la differenza tra questo riferimento e un oggetto? Abbiamo solo bisogno di un oggetto che rappresenti quella che era la classe. Ora l'oggetto rappresenta la vecchia classe e potrebbe implementare una nuova interfaccia che include i vecchi metodi statici, che ora non sono statici.

I metaclassi servono a questo scopo. Puoi provare la classe Class of Java. Ma il problema è che Java non è abbastanza flessibile per questo. Non è possibile dichiarare un metodo nell'oggetto classe di un'interfaccia.

Questo è un meta-problema - quando devi fare il culo

..blah blah

comunque hai una soluzione semplice: rendere il metodo non statico con la stessa logica. Ma poi dovresti prima creare un oggetto per chiamare il metodo.


0

Per risolvere questo: errore: body del metodo mancante, o dichiarare il vuoto statico astratto main (String [] args);

interface I
{
    int x=20;
    void getValue();
    static void main(String[] args){};//Put curly braces 
}
class InterDemo implements I
{
    public void getValue()
    {
    System.out.println(x);
    }
    public static void main(String[] args)
    {
    InterDemo i=new InterDemo();
    i.getValue();   
    }

}

uscita: 20

Ora possiamo usare il metodo statico nell'interfaccia


1
È inutile, però. La definizione di un metodo statico su un'interfaccia non impone ulteriori definizioni nelle classi che implementano tale interfaccia. Se rimuovi del tutto il metodo statico dall'interfaccia I, il tuo codice verrà compilato ed eseguito comunque senza problemi. In altre parole, NON state ignorando il metodo principale dell'interfaccia I nella classe InterDemo, ma solo creando un nuovo metodo con la stessa firma.
Fran Marzoa,

-2

Penso che Java non abbia metodi di interfaccia statica perché non ne hai bisogno. Puoi pensare di farlo, ma ... Come li useresti? Se vuoi chiamarli come

MyImplClass.myMethod()

quindi non è necessario dichiararlo nell'interfaccia. Se vuoi chiamarli come

myInstance.myMethod()

quindi non dovrebbe essere statico. Se hai intenzione di utilizzare il primo modo, ma vuoi solo imporre a ogni implementazione di avere un tale metodo statico, allora è davvero una convenzione di codifica, non un contratto tra istanza che implementa un'interfaccia e un codice chiamante.

Le interfacce consentono di definire il contratto tra l'istanza della classe che implementa l'interfaccia e il codice chiamante. E java ti aiuta a essere sicuro che questo contratto non è stato violato, quindi puoi fare affidamento su di esso e non preoccuparti di quale classe implementa questo contratto, solo "qualcuno che ha firmato un contratto" è sufficiente. In caso di interfacce statiche il tuo codice

MyImplClass.myMethod()

non fa affidamento sul fatto che ogni implementazione di interfaccia abbia questo metodo, quindi non hai bisogno di Java per aiutarti ad esserne sicuro.


-5

Qual è la necessità del metodo statico nell'interfaccia, i metodi statici vengono utilizzati fondamentalmente quando non è necessario creare un'istanza di oggetto. L'intera idea dell'interfaccia è quella di introdurre concetti OOP con l'introduzione del metodo statico che si sta deviando dal concetto.

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.