risposta-alla-domanda-sullo-sviluppo-web-bd.com

Interfacce Marker in Java?

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 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 dell'interfaccia Serializable il metodo writeObject(Object) di ObjectOutputStream fa qualcosa come instanceOf Serializable per rilevare se la classe implementa Serializable e lancia NotSerializableException di conseguenza . Tutto viene gestito nel codice e questo sembra essere un modello di progettazione quindi penso possiamo definire le nostre interfacce marker.

Ora i miei dubbi:

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

  2. E invece di usare l'operatore instanceOf perché il metodo non può essere qualcosa come writeObject(Serializable) in modo che ci sia un controllo del tipo in fase di compilazione piuttosto che in runtime?

  3. In che modo le annotazioni sono migliori delle Marker Interfaces?

122
Xavier DSouza
  1. La definizione di un'interfaccia marker menzionata sopra nel primo punto è errata? - È corretto nelle parti che (1) un'interfaccia marker deve essere vuota, e (2) implementarla intende implicare un trattamento speciale della classe di implementazione. La parte che non è corretta è che implica che JVM o il compilatore tratterà gli oggetti di quella classe in modo diverso: è corretto osservare che è il codice della libreria di classi Java che tratta questi oggetti come clonabili, serializzabili, ecc. Ha niente a che fare con il compilatore o la JVM.
  2. invece di usare l'operatore instanceOf perché il metodo non può essere qualcosa come writeObject(Serializable) in modo che ci sia un controllo del tipo in fase di compilazione - Questo ti permette di evitare di inquinare il tuo codice con il nome dell'interfaccia marcatore quando un "plain Object " è necessario. Ad esempio, se si crea una classe che deve essere serializzabile e ha membri oggetto, si dovrebbe forzare a eseguire il cast o rendere i propri oggetti Serializable al momento della compilazione. Ciò è inopportuno, poiché l'interfaccia è priva di qualsiasi funzionalità.
  3. In che modo le annotazioni sono migliori di Marker Interfaces? - Ti permettono di raggiungere lo stesso scopo di trasmettere i metadati relativi alla classe ai suoi consumatori senza creare un tipo separato per essa. Le annotazioni sono anche più potenti, lasciando che i programmatori trasmettano informazioni più sofisticate alle classi che "lo consumano".
105
dasblinkenlight

Non è possibile forzare Serializable su writeObject perché i figli di una classe non serializzabile possono essere serializzabili, ma possono essere ricondotti alla classe genitore. Di conseguenza, mantenere un riferimento a qualcosa di non serializzabile (come Object) non significa che l'istanza indicata non possa essere serializzata. Ad esempio in

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

la classe genitore (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 verrebbe eseguita.

18
h22

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

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

5
vidya k n

un'interfaccia marker A/A come suggerisce il nome, esiste solo per notificare tutto ciò che ne sa che una classe dichiara qualcosa. Il nulla può essere le classi JDK per l'interfaccia Serializable, o qualsiasi classe che scrivi yoursel per una personalizzata.

b/Se è 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é tu ne hai bisogno

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

4
Serge Ballesta
  1. Non ha nulla a che fare (necessariamente) con la JVM e con i compilatori, Ha qualcosa a che fare con qualsiasi codice che sia interessato ed è Verifica per una determinata interfaccia marker.

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

  3. Riguardo a questo particolare argomento, non penso che sia una questione di essere migliori o peggiori. L'interfaccia del marker sta facendo quello che è Dovrebbe fare bene.

3
peter.petrov

un. Li ho sempre visti come un motivo di progettazione e niente JVM-Special ho usato quel modello in diverse situazioni.

c. Credo che usare Annotazioni per contrassegnare qualcosa sia una soluzione migliore quindi utilizzare le interfacce marcatore. Semplicemente perché le interfacce sono in primo luogo volte a definire interfacce comuni di tipi/classi. Fanno parte della gerarchia di classe.

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
treeno

Lo scopo principale delle interfacce marker è di creare tipi speciali in cui i tipi stessi non hanno un loro proprio comportamento. 

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 solo gli oggetti delle classi che implementano l'interfaccia MarkerEntity vengano salvati, per gli altri tipi viene generata l'eccezione InvalidEntityFoundException. Quindi, qui l'interfaccia MarkerEntity marker sta definendo un tipo che aggiunge un comportamento speciale alle classi che lo implementano.

Sebbene le annotazioni possano essere utilizzate anche ora per contrassegnare le classi per alcuni trattamenti speciali, le annotazioni dei marcatori sono sostituite per il modello di denominazione e non per le interfacce Marker. 

Ma le annotazioni dei marker non possono sostituire completamente le interfacce marker perché; le interfacce marcatore sono usate per definire il tipo (come già spiegato sopra) dove le annotazioni del marcatore no.

Fonte per il commento all'interfaccia marcatore

2
infoj

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

Le interfacce marcatore sono generalmente utilizzate per uno dei due scopi:

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

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

È complicato e fastidioso digitare e, cosa ancora più importante, difficile da capire. Considera questo invece:

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

Quindi il tuo metodo si presenta così:

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

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

2) Le interfacce Marker possono anche essere utilizzate come un modo per aggirare la mancanza di tipi di intersezione di Java. Con un'interfaccia marcatore, puoi richiedere che ci siano due tipi diversi, come nella firma di un metodo. Supponiamo che tu abbia un widget di interfaccia nella tua applicazione, come descritto sopra. Se hai un metodo che richiede un Widget che ti capita di farlo scorrere (è 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
MikeyB

Ho fatto una semplice dimostrazione per risolvere i dubbi n. 1 e 2:

Avremo un'interfaccia mobile che sarà implementata da MobilePhone.Java Class e un'altra classe LandlinePhone.Java che faNOTimplementa 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 eccezioni personalizzate: pacchetto com;

classe pubblica NotMovableException estende l'eccezione {

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, quale classe implementa l'interfaccia marker mobile, passerà il test altrimenti verrà visualizzato un messaggio di errore. 

Questo è il modo in cui viene eseguito il controllo dell'istanzaOf per Serializable, Cloneable ecc 

1
Shashank Bodkhe

Se un'interfaccia non contiene alcun metodo e implementando tale interfaccia se il nostro oggetto otterrà una certa capacità, tali interfacce verranno chiamate interfacce marker.

0
yogesh kumar