web-dev-qa-db-fra.com

Interfaces de marqueur en Java?

On m'apprenait que l'interface Marker en Java est une interface vide et est utilisée pour signaler au compilateur ou à la machine virtuelle Java que les objets de la classe implémentant cette interface doivent être traités de manière particulière, comme la sérialisation, le clonage, etc.

Mais dernièrement, j'ai appris que cela n'avait en réalité rien à voir avec le compilateur ou la JVM. Par exemple, dans le cas de l'interface Serializable, la méthode writeObject(Object) de ObjectOutputStream effectue quelque chose comme instanceOf Serializable pour détecter si la classe implémente Serializable & jette NotSerializableException en conséquence . nous pouvons définir nos propres interfaces de marqueur.

Maintenant mes doutes:

  1. La définition d'une interface de marqueur mentionnée ci-dessus au 1er point est-elle fausse? Comment pouvons-nous définir une interface de marqueur alors?

  2. Et au lieu d'utiliser l'opérateur instanceOf, pourquoi la méthode ne peut-elle pas ressembler à writeObject(Serializable), de sorte qu'il existe une vérification du type à la compilation plutôt que l'exécution?

  3. Comment les annotations sont-elles meilleures que les interfaces de marqueur?

122
Xavier DSouza
  1. La définition d'une interface de marqueur mentionnée ci-dessus au 1er point est-elle fausse? - Il est correct dans les parties que (1) une interface de marqueur doit être vide et (2) sa mise en œuvre est censée impliquer un traitement spécial de la classe de mise en œuvre. La partie qui est incorrecte est que cela implique que JVM ou le compilateur traiteraient les objets de cette classe différemment: vous avez raison de remarquer que c'est le code de la bibliothèque de classes Java qui traite ces objets comme clonables, sérialisables, etc. rien à voir avec le compilateur ou la JVM.
  2. au lieu d'utiliser l'opérateur instanceOf, pourquoi la méthode ne peut-elle pas ressembler à writeObject(Serializable) de sorte qu'il y ait une vérification du type à la compilation - Cela vous permet d'éviter de polluer votre code avec le nom de l'interface du marqueur lorsqu'un "plain Object " est nécessaire. Par exemple, si vous créez une classe devant être sérialisable et comportant des membres d'objet, vous serez obligé de faire un transtypage ou de rendre vos objets Serializable au moment de la compilation. Ceci est gênant, car l’interface est dépourvue de toute fonctionnalité.
  3. Comment les annotations sont meilleures que les interfaces de marqueur? - Ils vous permettent d'atteindre le même objectif de transmission de métadonnées sur la classe à ses consommateurs sans créer de type distinct pour celle-ci. Les annotations sont également plus puissantes, ce qui permet aux programmeurs de transmettre des informations plus sophistiquées aux classes qui les "consomment".
105
dasblinkenlight

Il n'est pas possible d'appliquer Serializable sur writeObject car les enfants d'une classe non sérialisable peuvent être sérialisables, mais ils peuvent être retransmis en amont vers la classe parent. Par conséquent, le maintien d'une référence à quelque chose de non-sérialisable (comme Object) ne signifie pas que l'instance référencée ne peut pas vraiment être sérialisée. Par exemple dans

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

la classe parente (Object) n'est pas sérialisable et serait initialisée à l'aide de son constructeur sans paramètre. La valeur référencée par x, String, est sérialisable et l'instruction conditionnelle est exécutée.

18
h22

Une interface de marqueur en Java est une interface sans champs ni méthodes. Plus simplement, une interface vide en Java s'appelle une interface de marqueur. Des exemples d'interfaces de marqueur sont les interfaces Serializable, Cloneable et Remote. Celles-ci sont utilisées pour indiquer certaines informations aux compilateurs ou aux machines virtuelles. Ainsi, si la machine virtuelle Java constate qu'une classe est Serializable, elle peut effectuer une opération spéciale sur celle-ci. De même, si la machine virtuelle Java constate qu'une classe implémente Cloneable, elle peut effectuer certaines opérations pour prendre en charge le clonage. Il en va de même pour RMI et l'interface Remote. En bref, une interface de marqueur indique un signal ou une commande au compilateur ou à la machine virtuelle Java.

Ce qui précède a commencé comme une copie de un article de blog mais a été légèrement modifié pour la grammaire.

5
vidya k n

a/Une interface de marqueur, comme son nom le suggère, n'existe que pour notifier à tout ce qui le sait qu'une classe déclare quelque chose. Tout peut être les classes JDK pour l'interface Serializable ou toute classe que vous écrivez vous-même pour une classe personnalisée.

b/S'il s'agit d'une interface de marqueur, cela ne devrait impliquer l'existence d'aucune méthode - il serait préférable d'inclure la méthode implicite dans l'interface. Mais vous pouvez décider de le concevoir comme vous le souhaitez si vous savez pourquoi vous en avez besoin

c/Il y a peu de différence entre une interface vide et une annotation qui n'utilise ni valeur ni paramètre. Mais la différence est là: une annotation peut déclarer une liste de clés/valeurs qui seront accessibles au moment de l'exécution.

4
Serge Ballesta
  1. Cela n'a rien à voir (nécessairement) avec la machine virtuelle Java et les compilateurs, mais plutôt avec tout code qui intéresse et teste une interface de marqueur donnée.

  2. C'est une décision de conception et c'est fait pour une bonne raison. Voir la réponse De Audrius Meškauskas.

  3. En ce qui concerne ce sujet particulier, je ne pense pas que ce soit une question d’être meilleur ou pire. L’interface du marqueur fait ce qu’elle est supposée bien faire.

3
peter.petrov

une. Je les ai toujours vus comme un motif et rien JVM-Special, j’ai utilisé ce motif dans plusieurs situations.

c. Je pense qu’utiliser Annotations pour marquer quelque chose est une meilleure solution que d’utiliser des interfaces de marqueur. Tout simplement parce que les interfaces sont en premier lieu destinées à définir des interfaces communes de types/classes. Ils font partie de la hiérarchie de classe.

Les annotations visent à fournir des méta-informations au code, et je pense que ces marqueurs sont des méta-informations. Donc, ils sont exactement pour ce cas d'utilisation.

3
treeno

Le principal objectif des interfaces de marqueur est de créer des types spéciaux où les types eux-mêmes n’ont pas de comportement propre. 

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

Ici, la méthode save permet de s'assurer que seuls les objets des classes qui implémentent l'interface MarkerEntity sont enregistrés. Pour les autres types, InvalidEntityFoundException est levée. Donc, ici, l’interface marqueur MarkerEntity définit un type qui ajoute un comportement spécial aux classes qui l’implémentent.

Bien que les annotations puissent également être utilisées maintenant pour marquer des classes pour certains traitements spéciaux, les annotations de marqueur remplacent le modèle de dénomination et non les interfaces de marqueur. 

Mais les annotations de marqueur ne peuvent pas remplacer complètement les interfaces de marqueur car; Les interfaces de marqueur sont utilisées pour définir le type (comme déjà expliqué ci-dessus), contrairement aux annotations de marqueur.

Source pour le commentaire d'interface de marqueur

2
infoj

Je dirais d’abord que Serializable et Cloneable sont de mauvais exemples d’interfaces de marqueur. Bien sûr, ce sont des interfaces avec des méthodes, mais elles impliquent des méthodes, telles que writeObject(ObjectOutputStream). (Le compilateur créera une méthode writeObject(ObjectOutputStream) pour vous si vous ne l’écrivez pas et que tous les objets ont déjà clone(), mais il créera à nouveau une méthode clone() pour vous, mais avec des réserves. ne sont pas de bons exemples de conception.)

Les interfaces de marqueur sont généralement utilisées à l'une des deux fins suivantes:

1) Comme raccourci pour éviter un type excessivement long, ce qui peut arriver avec beaucoup de génériques. Par exemple, supposons que vous ayez cette signature de méthode:

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

C'est désordonné et ennuyeux à taper, et surtout, difficile à comprendre. Considérez ceci à la place:

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

Ensuite, votre méthode ressemble à ceci:

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

Non seulement c'est plus clair, mais vous pouvez maintenant utiliser Javadoc l'interface du widget, et il est également plus facile de rechercher toutes les occurrences dans votre code de Widget.

2) Les interfaces de marqueur peuvent également être utilisées pour pallier le manque de types d'intersection de Java. Avec une interface de marqueur, vous pouvez exiger que quelque chose soit de deux types différents, comme dans une signature de méthode. Supposons que vous ayez un widget d'interface dans votre application, comme nous l'avons décrit ci-dessus. Si votre méthode nécessite un widget qui vous permet également de le parcourir (c'est artificiel, mais travaillez avec moi ici), votre seule bonne solution consiste à créer une interface de marqueur qui étend les deux interfaces:

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

Et dans votre code:

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

J'ai fait une démonstration simple pour résoudre le doute n ° 1 et 2:

Nous aurons une interface Movable qui sera implémentée par MobilePhone.Java Class et une classe supplémentaire LandlinePhone.Java qui n'utilise PAS pour implémenter l'interface Movable

Notre interface de marqueur: 

package com;

public interface Movable {

}

LandLinePhone.Java et MobilePhone.Java

 package com;

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

Notre classe d'exception personnalisée: paquet com;

classe publique NotMovableException étend Exception {

private static final long serialVersionUID = 1L;

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

Notre classe de 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");
}}

Maintenant, quand on exécute 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)

Quelle que soit la classe implémentant l'interface de marqueur, Movable réussira le test, sinon un message d'erreur s'affichera. 

C’est la façon dont l’opérateur instanceOf est vérifié pour Serializable, Cloneable, etc. 

1
Shashank Bodkhe

Si une interface ne contient aucune méthode et en implémentant cette interface si notre objet aura une certaine capacité, ce type d'interfaces est appelé interface marqueur.

0
yogesh kumar