On m'a appris que l'interface Marker en Java est une interface vide et est utilisée pour signaler au compilateur ou à la JVM que les objets de la classe implémentant cette interface doivent être traités d'une manière spéciale, comme la sérialisation, le clonage, etc.
Mais dernièrement, j'ai appris que cela n'avait en fait rien à voir avec le compilateur ou la JVM. Par exemple, dans le cas de l' Serializable
interface, la méthode writeObject(Object)
de ObjectOutputStream
fait quelque chose comme instanceOf Serializable
pour détecter si la classe implémente Serializable
& lance en NotSerializableException
conséquence. Tout est géré dans le code et cela semble être un modèle de conception, donc je pense que nous pouvons définir nos propres interfaces de marqueurs.
Maintenant mes doutes:
La définition d'une interface de marqueur mentionnée ci-dessus au 1er point est-elle fausse? Comment définir alors une interface Marker?
Et au lieu d'utiliser l'
instanceOf
opérateur, pourquoi la méthode ne peut-elle pas être quelque chose comme celawriteObject(Serializable)
afin qu'il y ait une vérification de type au moment de la compilation plutôt que l'exécution?En quoi les annotations sont-elles meilleures que les interfaces de marqueurs?
la source
Serializable
comme une annotation est un non-sens et@NonNull
comme une interface est un non-sens. Je dirais: les annotations sont des marqueurs + des métadonnées. BTW: Forefunner of Annotations était XDoclet, né à Javadoc, tué par des annotations.Réponses:
writeObject(Serializable)
pour qu'il y ait une vérification de type à la compilation - Cela vous permet d'éviter de polluer votre code avec le nom de l'interface du marqueur lorsqu'un "plainObject
" est nécessaire. Par exemple, si vous créez une classe qui doit être sérialisable et qui a des membres d'objet, vous seriez obligé de faire un casting ou de créer vos objetsSerializable
au moment de la compilation. Ceci est peu pratique, car l'interface est dépourvue de toute fonctionnalité.la source
writeObject
c'est privé, cela signifie que par exemple une classe n'a pas besoin d'appeler l'implémentation de la superclasseCloneable
il n'est pas clair s'il s'agit d'une bibliothèque ou d'un traitement JVM de l'instance qui est modifiée.Il est impossible de faire respecter
Serializable
lewriteObject
fait que les enfants de la classe non-sérialisable peuvent être sérialisable, mais leurs instances peut être de retour upcasted à la classe parente. Par conséquent, conserver une référence à quelque chose de non sérialisable (commeObject
) ne signifie pas que l'instance référencée ne peut pas être vraiment sérialisée. Par exemple dansla classe parent (
Object
) n'est pas sérialisable et serait initialisée à l'aide de son constructeur sans paramètre. La valeur référencée parx
,String
est sérialisable et l'instruction conditionnelle courrait.la source
Ce qui précède a commencé comme une copie d' un article de blog mais a été légèrement modifié pour la grammaire.
la source
J'ai fait une démonstration simple pour résoudre les doutes n ° 1 et 2:
Nous aurons une interface Movable qui sera implémentée par
MobilePhone.java
Class et une autre classeLandlinePhone.java
qui n'implémentera PAS l' interface MovableNotre interface de marqueur:
LandLinePhone.java
etMobilePhone.java
Notre classe d'exception personnalisée: package com;
Notre classe de test:
TestMArkerInterface.java
Maintenant, quand nous exécutons la classe principale:
Donc, quelle que soit la classe implémente l'interface de marqueur
Movable
le test sera réussi, sinon le message d'erreur sera affiché.C'est la façon dont la
instanceOf
vérification de l'opérateur est effectuée pour Serializable , Cloneable, etc.la source
a / Une interface de marqueur, comme son nom l'indique, n'existe que pour notifier tout ce qui en sait qu'une classe déclare quelque chose. Le tout peut être les classes JDK pour l'
Serializable
interface, 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 aucune valeur ou 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.
la source
une. Je les ai toujours vus comme un modèle de conception et rien de spécial JVM J'ai utilisé ce modèle dans plusieurs situations.
c. Je crois que l'utilisation d'annotations pour marquer quelque chose est une meilleure solution que l'utilisation d'interfaces de marqueurs. Simplement parce que les Interfaces visent en premier lieu à définir des interfaces communes de Types / Classes. Ils font partie de la hiérarchie des classes.
Les annotations visent à fournir des méta-informations au code, et je pense que les marqueurs sont des méta-informations. Donc, ils sont exactement pour ce cas d'utilisation.
la source
Cela n'a rien à voir (nécessairement) avec la JVM et les compilateurs, cela a quelque chose à voir avec n'importe quel code qui est intéressé et teste une interface de marqueur donnée.
C'est une décision de conception et c'est fait pour une bonne raison. Voir la réponse d'Audrius Meškauskas.
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 censée faire très bien.
la source
L'objectif principal des interfaces de marqueur est de créer des types spéciaux où les types eux-mêmes n'ont aucun comportement propre.
Ici, la méthode save garantit 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 de marqueur MarkerEntity définit un type qui ajoute un comportement spécial aux classes l'implémentant.
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) alors que les annotations de marqueur ne le font pas.
Source du commentaire de l'interface du marqueur
la source
Je dirais tout d'abord que Serializable et Cloneable sont de mauvais exemples d'interfaces de marqueurs. 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 unewriteObject(ObjectOutputStream)
méthode pour vous si vous ne la remplacez pas, et tous les objets l'ont déjà faitclone()
, mais le compilateur créera à nouveau uneclone()
méthode réelle pour vous, mais avec des mises en garde. Ces deux cas sont étranges qui ne le sont pas vraiment bons exemples de conception.)Les interfaces de marqueurs sont généralement utilisées à deux fins:
1) En tant que raccourci pour éviter un type trop long, ce qui peut arriver avec beaucoup de génériques. Par exemple, disons que vous avez cette signature de méthode:
C'est compliqué et ennuyeux à taper, et plus important encore, difficile à comprendre. Considérez plutôt ceci:
Ensuite, votre méthode ressemble à ceci:
Non seulement c'est plus clair, mais vous pouvez maintenant 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 marqueurs peuvent également être utilisées pour contourner 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 vous avez une méthode qui nécessite un widget qui vous permet également de l'itérer (c'est artificiel, mais travaillez avec moi ici), votre seule bonne solution est de créer une interface de marqueur qui étend les deux interfaces:
Et dans votre code:
la source
Serializable
ouCloneable
. Vous pouvez le vérifier en inspectant vos fichiers de classe. De plus, la création «d'interfaces de raccourcis» n'est pas l' objectif des interfaces de marqueur. Et c'est une très mauvaise pratique de codage car elle nécessiterait la création de classes d' implémentation supplémentaires pour remplir les interfaces supplémentaires. À propos, Java a des types d'intersection depuis une décennie maintenant. En savoir plus sur les génériques…Si une interface ne contient aucune méthode et en implémentant cette interface, si notre objet obtient une certaine capacité, ce type d'interface est appelé interfaces de marqueur.
la source