Marker Interfaces in Java?


134

Mi è stato insegnato che l'interfaccia Marker in Java è un'interfaccia vuota e viene utilizzata per segnalare al compilatore o alla JVM che gli oggetti della classe che implementano questa interfaccia devono essere trattati in un modo speciale, come la serializzazione, la clonazione, ecc.

Ma ultimamente ho imparato che in realtà non ha nulla a che fare con il compilatore o la JVM. Ad esempio, nel caso di Serializableinterfaccia del metodo writeObject(Object)di ObjectOutputStreamfa qualcosa di simile instanceOf Serializableper rilevare se gli attrezzi di classe Serializablee getta NotSerializableExceptiondi conseguenza. Tutto è gestito nel codice e questo sembra essere un modello di progettazione, quindi penso che possiamo definire le nostre interfacce marker.

Ora i miei dubbi:

  1. La definizione di un'interfaccia marker sopra menzionata al 1 ° punto è errata? Come possiamo definire un'interfaccia Marker allora?

  2. E invece di utilizzare l' instanceOfoperatore, perché il metodo non può essere simile a writeObject(Serializable)quello in modo che ci sia un controllo del tipo di compilazione anziché il runtime?

  3. In che modo le annotazioni sono migliori delle interfacce marker?


8
Serializablecome un'annotazione è una sciocchezza e @NonNullcome un'interfaccia è una sciocchezza. Direi: le annotazioni sono marker + metadati. A proposito: Forefunner of Annotations era XDoclet, nato a Javadoc, ucciso da Annotations.
Grim

Risposte:


117
  1. La definizione di un'interfaccia marker sopra menzionata al 1 ° punto è errata? - È corretto nelle parti che (1) un'interfaccia marker deve essere vuota e (2) implementarla implica un trattamento speciale della classe di implementazione. La parte errata è che implica che JVM o il compilatore tratteranno gli oggetti di quella classe in modo diverso: hai ragione nell'osservare che è il codice della libreria di classi Java che tratta questi oggetti come clonabili, serializzabili, ecc. niente a che fare con il compilatore o la JVM.
  2. invece di utilizzare l'operatore instanceOf perché il metodo non può essere simile a writeObject(Serializable)quello in modo che ci sia un controllo del tipo in fase di compilazione - Ciò consente di evitare di inquinare il codice con il nome dell'interfaccia del marcatore quando Objectè necessario un "semplice ". Ad esempio, se si crea una classe che deve essere serializzabile e ha membri oggetto, si sarebbe costretti a eseguire il casting o creare i propri oggetti Serializablein fase di compilazione. Questo è scomodo, perché l'interfaccia è priva di qualsiasi funzionalità.
  3. In che modo le annotazioni sono migliori delle interfacce marker? - Ti consentono di raggiungere lo stesso scopo di trasmettere metadati sulla classe ai suoi consumatori senza crearne un tipo separato. Anche le annotazioni sono più potenti, consentendo ai programmatori di trasmettere informazioni più sofisticate alle classi che le "consumano".

14
Il modo in cui l'ho sempre capito è che le annotazioni sono una sorta di "Marker Interfaces 2.0": la serializzazione esiste da Java 1.1, le annotazioni sono state aggiunte in 1.5
blagae,

e poiché writeObjectè privato, ciò significa che per esempio una classe non deve chiamare l'implementazione della superclasse
maniaco del cricchetto

15
Una cosa da tenere a mente è che le annotazioni sono state aggiunte alla lingua alcuni anni dopo la progettazione della libreria standard. Se le annotazioni fossero state nella lingua dall'inizio, è dubbio che Serializable sarebbe stata un'interfaccia, probabilmente sarebbe stata un'annotazione.
Theodore Norvell,

Bene, nel caso Cloneablenon sia chiaro se si tratta di una libreria o di un trattamento JVM dell'istanza che viene modificata.
Holger,

"[...] senza creare un tipo separato per esso." - Direi che questo è esattamente ciò che li separa: Un'interfaccia marcatore fa introdurre un tipo, mentre le annotazioni (tipo di) does't.
aioobe,

22

Non è possibile imporre Serializablel' applicazione writeObjectperché i figli di una classe non serializzabile possono essere serializzabili, ma le loro istanze possono essere riportate alla classe padre. Di conseguenza, tenere un riferimento a qualcosa di non serializzabile (come Object) non significa che l'istanza di riferimento non possa essere realmente serializzata. Ad esempio in

   Object x = "abc";
   if (x instanceof Serializable) {
   }

la classe parent ( Object) non è serializzabile e verrebbe inizializzata usando il suo costruttore senza parametri. Il valore a cui fa riferimento x, Stringè serializzabile e l'istruzione condizionale correrebbe.


6

Un'interfaccia marker in Java è un'interfaccia senza campi o metodi. In parole povere, un'interfaccia vuota in Java si chiama interfaccia marker. Esempi di interfacce marcatori sono i Serializable, Cloneablee le Remoteinterfacce. Questi sono usati per indicare alcune informazioni a compilatori o JVM. Quindi, se la JVM vede una classe Serializable, può fare qualche operazione speciale su di essa. Allo stesso modo, se JVM vede l'implementazione di alcune classi Cloneable, può eseguire alcune operazioni per supportare la clonazione. Lo stesso vale per RMI e l' Remoteinterfaccia. Quindi, in breve, un'interfaccia marcatore indica un segnale o un comando al compilatore o alla JVM.

Quanto sopra è iniziato come una copia di un post sul blog ma è stato leggermente modificato per la grammatica.


6
Va bene copiare ma per favore menziona anche la fonte: javarevisited.blogspot.com/2012/01/… . Inoltre sarà bello se non copi incolla anche gli errori di ortografia. :)
Saurabh Patil,

6

Ho fatto una semplice dimostrazione per risolvere il dubbio n. 1 e 2:

Avremo un'interfaccia mobile che verrà implementata dalla MobilePhone.javaclasse e un'altra classe LandlinePhone.javache NON implementa l'interfaccia mobile

La nostra interfaccia marker:

package com;

public interface Movable {

}

LandLinePhone.java e MobilePhone.java

 package com;

 class LandLinePhone {
    // more code here
 }
 class MobilePhone implements Movable {
    // more code here
 }

La nostra classe di eccezione personalizzata: pacchetto com;

public class NotMovableException extends Exception {

private static final long serialVersionUID = 1L;

    @Override
    public String getMessage() {
        return "this object is not movable";
    }
    // more code here
    }

La nostra classe di test: TestMArkerInterface.java

package com;

public class TestMarkerInterface {

public static void main(String[] args) throws NotMovableException {
    MobilePhone mobilePhone = new MobilePhone();
    LandLinePhone landLinePhone = new LandLinePhone();

    TestMarkerInterface.goTravel(mobilePhone);
    TestMarkerInterface.goTravel(landLinePhone);
}

public static void goTravel(Object o) throws NotMovableException {
    if (!(o instanceof Movable)) {
        System.out.println("you cannot use :" + o.getClass().getName() + "   while travelling");
        throw new NotMovableException();
    }

    System.out.println("you can use :" + o.getClass().getName() + "   while travelling");
}}

Ora quando eseguiamo la classe principale:

you can use :com.MobilePhone while travelling
you cannot use :com.LandLinePhone while travelling
Exception in thread "main" com.NotMovableException: this object is not movable
    at com.TestMarkerInterface.goTravel(TestMarkerInterface.java:22)
    at com.TestMarkerInterface.main(TestMarkerInterface.java:14)

Quindi, ogni classe implementa l'interfaccia marcatore Movable passerà il messaggio di errore test altrimenti verrà visualizzato.

Questo è il modo in cui instanceOfviene eseguito il controllo dell'operatore per serializzabile , clonabile , ecc


5

un'interfaccia marcatore / A come suggerisce il nome esiste solo per avvisare tutto ciò che sa che una classe dichiara qualcosa. Tutto può essere le classi JDK per l' Serializableinterfaccia o qualsiasi classe che scrivi per una personalizzata.

b / Se si tratta di un'interfaccia marcatore, non dovrebbe implicare l'esistenza di alcun metodo: sarebbe meglio includere il metodo implicito nell'interfaccia. Ma puoi decidere di progettarlo come vuoi se sai perché ne hai bisogno

c / C'è poca differenza tra un'interfaccia vuota e un'annotazione che non utilizza alcun valore o parametro. Ma la differenza è lì: un'annotazione può dichiarare un elenco di chiavi / valori che saranno accessibili in fase di esecuzione.


3

un. Li ho sempre visti come un modello di design e niente di speciale JVM ho usato quel modello in diverse situazioni.

c. Credo che usare le annotazioni per contrassegnare qualcosa sia una soluzione migliore rispetto all'utilizzo delle interfacce marker. Semplicemente perché le interfacce sono in primo luogo volte a definire interfacce comuni di tipi / classi. Fanno parte della gerarchia di classi.

Le annotazioni hanno lo scopo di fornire meta-informazioni al codice e penso che i marcatori siano meta-informazioni. Quindi sono esattamente per quel caso d'uso.


3
  1. Non ha nulla a che fare (necessariamente) con la JVM e i compilatori, ha qualcosa a che fare con qualsiasi codice che è interessato e sta testando per una data interfaccia marcatore.

  2. È una decisione di progettazione ed è fatto per una buona ragione. Vedi la risposta di Audrius Meškauskas.

  3. Per quanto riguarda questo particolare argomento, non credo sia una questione di essere migliore o peggiore. L'interfaccia marker sta facendo quello che dovrebbe fare bene.


Puoi aggiungere un link alla "risposta di Audrius Meškauskas"? Non vedo nulla in questa pagina con quel nome.
Sarah Messer,

2

Lo scopo principale delle interfacce marker è quello di creare tipi speciali in cui i tipi stessi non hanno comportamenti propri.

public interface MarkerEntity {

}

public boolean save(Object object) throws InvalidEntityFoundException {
   if(!(object instanceof MarkerEntity)) {
       throw new InvalidEntityFoundException("Invalid Entity Found, can't be  saved);
   } 
   return db.save(object);
}

Qui il metodo save assicura che vengano salvati solo gli oggetti delle classi che implementano l'interfaccia MarkerEntity, per gli altri tipi viene lanciato InvalidEntityFoundException. Quindi qui l'interfaccia marcatore MarkerEntity sta definendo un tipo che aggiunge un comportamento speciale alle classi che lo implementano.

Sebbene ora le annotazioni possano essere utilizzate anche per contrassegnare le classi per alcuni trattamenti speciali, ma le annotazioni dei marker sostituiscono il modello di denominazione non per le interfacce Marker.

Ma le annotazioni dei marker non possono sostituire completamente le interfacce dei marker perché; le interfacce marker vengono utilizzate per definire il tipo (come già spiegato sopra), mentre le annotazioni marker non lo fanno.

Sorgente per il commento dell'interfaccia marker


1
+1 per dimostrare che viene effettivamente utilizzato come un semplice hook di "sicurezza" che un programmatore deve dire esplicitamente che può essere salvato ad esempio in un database.
Ludvig W

1

Direi per prima cosa che Serializable e Cloneable sono cattivi esempi di interfacce marker. Certo, sono interfacce con i metodi, ma implicano metodi come writeObject(ObjectOutputStream). (Il compilatore creerà un writeObject(ObjectOutputStream)metodo per te se non lo sovrascrivi e tutti gli oggetti lo hanno già clone(), ma il compilatore creerà di nuovo un clone()metodo reale per te ma con avvertimenti. Entrambi questi sono strani casi limite che in realtà non lo sono buoni esempi di design.)

Le interfacce dei marker vengono generalmente utilizzate per uno di questi due scopi:

1) Come scorciatoia per evitare un tipo eccessivamente lungo, che può accadere con molti generici. Ad esempio, supponiamo di avere questa firma del metodo:

public void doSomething(Foobar<String, Map<String, SomethingElse<Integer, Long>>>) { ... }

È disordinato e fastidioso da digitare e, soprattutto, difficile da capire. Considera questo invece:

public interface Widget extends Foobar<String, Map<String, SomethingElse<Integer, Long>>> { }

Quindi il tuo metodo è simile al seguente:

public void doSomething(Widget widget) { ... }

Non solo è più chiaro, ma ora puoi Javadoc l'interfaccia del Widget, ed è anche più facile cercare tutte le occorrenze nel tuo codice del Widget.

2) Le interfacce dei marker possono anche essere utilizzate per aggirare la mancanza di tipi di intersezione di Java. Con un'interfaccia marcatore, puoi richiedere che qualcosa sia di due tipi diversi, come nella firma di un metodo. Supponi di avere un widget di interfaccia nella tua applicazione, come abbiamo descritto sopra. Se hai un metodo che richiede un Widget che ti permette anche di iterare su di esso (è inventato, ma lavora con me qui), la tua unica buona soluzione è creare un'interfaccia marker che estenda entrambe le interfacce:

public interface IterableWidget extends Iterable<String>, Widget { }

E nel tuo codice:

public void doSomething(IterableWidget widget) {
    for (String s : widget) { ... }
}

1
Il compilatore non crea alcun metodo se la tua classe implementa Serializableo Cloneable. Puoi verificarlo controllando i tuoi file di classe. Inoltre, la creazione di "interfacce di scelta rapida" non riguarda le interfacce marker. Ed è davvero una cattiva pratica di codifica poiché richiederebbe la creazione di ulteriori classi di implementazione per soddisfare le interfacce aggiuntive. A proposito, Java ha tipi di intersezione ormai da un decennio. Ulteriori informazioni su Generics ...
Holger,

Per la clonazione, hai ragione. Cambia ciò che fa Object.clone (). È ancora orribile. Vedi collegamento Josh Bloch Le interfacce di collegamento non sono necessariamente un buon modello di progettazione, poiché limiti arbitrariamente ciò che puoi inviare a un metodo. Allo stesso tempo, sento che scrivere in modo più chiaro, seppur leggermente più restrittivo, di solito è un compromesso ragionevole. Per quanto riguarda i tipi di intersezione, questo vale solo per i generici, e non sono denotabili, e quindi inutili in molte occasioni. Prova ad avere una variabile di istanza che sia sia serializzabile che, bene, qualsiasi altra cosa.
MikeyB,

0

Se un'interfaccia non contiene alcun metodo e implementando tale interfaccia se il nostro oggetto avrà qualche capacità, questo tipo di interfacce sono chiamate interfacce marker.

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.