it-swarm.com.de

Markerschnittstellen in Java?

Mir wurde beigebracht, dass die Marker-Schnittstelle in Java eine leere Schnittstelle ist und dazu verwendet wird, dem Compiler oder der JVM zu signalisieren, dass die Objekte der Klasse, die diese Schnittstelle implementiert, auf besondere Weise behandelt werden müssen, z. B. Serialisierung, Klonen usw.

Aber in letzter Zeit habe ich gelernt, dass es eigentlich nichts mit dem Compiler oder der JVM zu tun hat. Im Fall von Serializable interface beispielsweise führt die Methode writeObject(Object) von ObjectOutputStream so etwas wie instanceOf Serializable aus, um festzustellen, ob die Klasse Serializable implementiert und NotSerializableException dementsprechend auslöst ..__ Alles wird im Code behandelt, und dies scheint ein Designmuster zu sein, also denke ich Wir können unsere eigenen Markerschnittstellen definieren.

Nun meine Zweifel:

  1. Ist die oben unter 1. Punkt erwähnte Definition einer Markerschnittstelle falsch? Wie definieren wir dann eine Marker-Schnittstelle?

  2. Und anstatt den Operator instanceOf zu verwenden, warum kann die Methode nicht etwas wie writeObject(Serializable) sein, so dass eine Überprüfung der Kompilierzeit statt einer Laufzeit stattfindet?

  3. Wie sind Annotationen besser als Marker-Interfaces?

122
Xavier DSouza
  1. Ist die oben unter 1. Punkt erwähnte Definition einer Markerschnittstelle falsch? - In den Teilen ist es richtig, dass (1) eine Markierungsschnittstelle leer sein muss und (2) ihre Implementierung eine besondere Behandlung der implementierenden Klasse impliziert. Der falsche Teil besteht darin, dass JVM oder der Compiler die Objekte dieser Klasse anders behandeln: Sie stellen zu Recht fest, dass der Code der Java-Klassenbibliothek diese Objekte als klonbar, serialisierbar usw. behandelt nichts mit dem Compiler oder der JVM zu tun.
  2. Statt den instanceOf-Operator zu verwenden, kann die Methode nicht etwas wie writeObject(Serializable) sein, sodass eine Überprüfung der Kompilierzeit erfolgt. - So können Sie vermeiden, dass Ihr Code mit dem Namen der Markierungsschnittstelle verschmutzt wird, wenn ein "plain Object" " wird gebraucht. Wenn Sie beispielsweise eine Klasse erstellen, die serialisierbar sein muss und über Objektmitglieder verfügt, müssen Sie entweder Casting ausführen oder Ihre Objekte zur Kompilierzeit Serializable erstellen. Dies ist unpraktisch, da die Schnittstelle keine Funktionalität hat.
  3. Wie sind Annotationen besser als Marker-Interfaces? - Sie können den gleichen Zweck erreichen, Metadaten über die Klasse an die Verbraucher zu übermitteln, ohne dafür einen eigenen Typ zu erstellen. Anmerkungen sind auch leistungsfähiger: Programmierer können ausgefeiltere Informationen an Klassen weitergeben, die sie "verbrauchen".
105
dasblinkenlight

Es ist nicht möglich, Serializable für writeObject zu erzwingen, da untergeordnete Elemente einer nicht serialisierbaren Klasse serialisierbar sein können. Sie können jedoch auf die übergeordnete Klasse zurückgesetzt werden. Wenn Sie einen Verweis auf etwas nicht serialisierbar halten (wie Object), bedeutet dies nicht, dass die referenzierte Instanz wirklich nicht serialisiert werden kann. Zum Beispiel in

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

die übergeordnete Klasse (Object) ist nicht serialisierbar und würde mit ihrem parameterlosen Konstruktor initialisiert. Der von x, String, referenzierte Wert ist serialisierbar und die Bedingungsanweisung würde ausgeführt.

18
h22

Eine Markerschnittstelle in Java ist eine Schnittstelle ohne Felder oder Methoden. Einfacher ausgedrückt, eine leere Schnittstelle in Java wird als Markerschnittstelle bezeichnet. Beispiele für Markerschnittstellen sind die Schnittstellen Serializable, Cloneable und Remote. Diese werden verwendet, um Compiler oder JVMs mit einigen Informationen zu versorgen. Wenn die JVM also sieht, dass eine Klasse Serializable ist, kann sie einige spezielle Operationen ausführen. Auf ähnliche Weise kann die JVM, wenn eine Klasse Cloneable implementiert, einige Vorgänge ausführen, um das Klonen zu unterstützen. Gleiches gilt für RMI und die Remote-Schnittstelle. Kurz gesagt, eine Markierungsschnittstelle zeigt dem Compiler oder der JVM ein Signal oder einen Befehl an.

Das Vorstehende begann als Kopie von einem Blogbeitrag , wurde aber leicht für die Grammatik bearbeitet.

5
vidya k n

eine A/A-Markierungsschnittstelle, wie der Name vermuten lässt, existiert nur, um alles, was darüber weißzu benachrichtigen, dass eine Klasse etwas deklariert. Das Alles können die JDK-Klassen für die Serializable-Schnittstelle sein oder jede Klasse, die Sie für eine benutzerdefinierte Klasse schreiben.

b/Wenn es sich um eine Marker-Schnittstelle handelt, sollte dies keine Existenz einer Methode implizieren. Es ist besser, die implizierte Methode in die Schnittstelle aufzunehmen. Sie können sich jedoch dafür entscheiden, es nach Ihren Wünschen zu gestalten, wenn Sie wissen, dass warumSie es brauchen

c/Es besteht ein geringer Unterschied zwischen einer leeren Schnittstelle und einer Anmerkung, die keinen Wert oder Parameter verwendet. Der Unterschied besteht jedoch darin, dass eine Anmerkung eine Liste von Schlüsseln/Werten deklarieren kann, auf die zur Laufzeit zugegriffen werden kann.

4
Serge Ballesta
  1. Es hat nichts (notwendigerweise) mit der JVM und den Compilern zu tun. Es hat etwas mit Code zu tun, der sich für eine bestimmte Markerschnittstelle interessiert.

  2. Es ist eine Designentscheidung, und das aus gutem Grund. Siehe die Antwort von Audrius Meškauskas.

  3. In Bezug auf dieses spezielle Thema denke ich nicht, dass es darum geht, besser oder schlechter zu sein. Die Markerschnittstelle macht genau das, was sie tun soll.

3
peter.petrov

ein. Ich habe sie immer als Designmuster gesehen und nichts JVM-Special. Ich habe dieses Muster in verschiedenen Situationen verwendet.

c. Ich glaube, die Verwendung von Annotations zum Markieren ist eine bessere Lösung als die Verwendung von Markerschnittstellen. Einfach deshalb, weil Schnittstellen in erster Linie darauf abzielen, gemeinsame Schnittstellen von Typen/Klassen zu definieren. Sie sind Teil der Klassenhierarchie.

Anmerkungen dienen dazu, Meta-Informationen zum Code bereitzustellen, und ich denke, dass Marker Meta-Informationen sind. Sie sind also genau für diesen Anwendungsfall.

3
treeno

Der Hauptzweck von Markerschnittstellen besteht darin, spezielle Typen zu erstellen, bei denen Typen selbst kein eigenes Verhalten haben. 

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

Hier stellt die save-Methode sicher, dass nur die Objekte von Klassen gespeichert werden, die die MarkerEntity-Schnittstelle implementieren. Bei anderen Typen wird InvalidEntityFoundException ausgelöst. Das MarkerEntity-Marker-Interface definiert hier einen Typ, der den implementierenden Klassen ein besonderes Verhalten verleiht.

Annotationen können zwar jetzt auch zum Markieren von Klassen für einige spezielle Behandlungen verwendet werden, Markierungskommentare ersetzen jedoch das Benennungsmuster, nicht die Markierungsschnittstellen. 

Markierungsanmerkungen können die Markierungsschnittstellen jedoch nicht vollständig ersetzen, weil; Markierungsschnittstellen werden verwendet, um den Typ zu definieren (wie oben bereits erläutert), wohingegen Markierungsanmerkungen dies nicht tun.

Quelle für Kommentar der Markierungsschnittstelle

2
infoj

Ich würde zunächst einmal argumentieren, dass Serializable und Cloneable schlechte Beispiele für Marker-Interfaces sind. Sicher, sie sind Schnittstellen zu Methoden, aber implizieren -Methoden wie writeObject(ObjectOutputStream). (Der Compiler erstellt eine writeObject(ObjectOutputStream)-Methode für Sie, wenn Sie sie nicht überschreiben, und alle Objekte verfügen bereits über clone(). Der Compiler erstellt jedoch wieder eine echte clone()-Methode, jedoch mit Vorbehalten. Beide Fälle sind seltsame Edge-Fälle, die wirklich sind sind keine guten Designbeispiele.)

Marker-Interfaces werden im Allgemeinen für zwei Zwecke verwendet:

1) Als Abkürzung, um einen zu langen Typ zu vermeiden, der bei vielen Generika vorkommen kann. Angenommen, Sie haben diese Methodensignatur:

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

Das ist chaotisch und nervig beim Tippen und vor allem schwer zu verstehen. Betrachten Sie das stattdessen:

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

Dann sieht Ihre Methode so aus:

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

Es ist nicht nur übersichtlicher, Sie können jetzt auch die Widget-Benutzeroberfläche von Javadoc verwenden. Außerdem ist es einfacher, alle Vorkommen in Ihrem Code für Widget zu suchen.

2) Marker-Interfaces können auch als Weg um die fehlenden Kreuzungstypen von Java verwendet werden. Mit einer Markierungsschnittstelle können Sie zwei verschiedene Arten von Objekten erfordern, z. B. eine Methodensignatur. Nehmen wir an, Sie haben ein Interface-Widget in Ihrer Anwendung, wie oben beschrieben. Wenn Sie über eine Methode verfügen, für die ein Widget erforderlich ist, über das Sie iterieren können (es ist zwar beabsichtigt, aber arbeiten Sie mit mir zusammen), ist die einzige gute Lösung die Erstellung einer Marker-Schnittstelle, die beide Schnittstellen erweitert:

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

Und in deinem Code:

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

Ich habe eine einfache Demonstration gemacht, um die Zweifel Nr. 1 und 2 zu lösen:

Wir werden eine bewegliche Schnittstelle haben, die von der MobilePhone.Java-Klasse implementiert wird, und eine weitere Klasse LandlinePhone.Java, dieNICHTeine Movable-Schnittstelle implementiert

Unsere Marker-Schnittstelle: 

package com;

public interface Movable {

}

LandLinePhone.Java und MobilePhone.Java

 package com;

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

Unsere benutzerdefinierte Ausnahmeklasse: Paket com;

die öffentliche Klasse NotMovableException erweitert die Ausnahme {

private static final long serialVersionUID = 1L;

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

Unsere Testklasse: 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");
}}

Wenn wir nun Hauptklasse ausführen: 

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)

Also, welche Klasse die Marker-Schnittstelle Movable durchläuft, wird die Fehlermeldung "Test else" bestanden. 

Dies ist die Art und Weise, in der die Instanz-Operator-Überprüfung für Serializable, Cloneable usw. durchgeführt wird 

1
Shashank Bodkhe

Wenn eine Schnittstelle keine Methode enthält und diese Schnittstelle implementiert wird, wenn unser Objekt einige Fähigkeiten erhält, werden diese Schnittstellen als Markerschnittstellen bezeichnet.

0
yogesh kumar