Pourquoi aurait-on déclarer un immuable classe final en Java?
J'ai lu que pour faire un classe immuable en Java, nous devons faire le suivant,
- Ne pas fournir toutes les poseurs de
- Marque tous les champs privés
- Faire la classe finale
Pourquoi l'étape 3? Pourquoi devrais-je marquer la classe final
?
java.math.BigInteger
classe est de donner l'exemple, c'est les valeurs sont immuables, mais elle n'est pas définitive.- Si vous avez un
BigInteger
, vous ne savez pas si il est immuable ou pas. C'est une foiré conception. /java.io.File
est un exemple plus intéressant. - Ne pas permettre à des sous-classes pour remplacer les méthodes - la façon La plus simple de le faire est de déclarer la classe comme final. Une approche plus sophistiquée consiste à rendre le constructeur privé et de construire des instances dans l'usine de méthodes de docs.oracle.com/javase/tutorial/essential/concurrency/...
- pouvez-vous expliquer (ou un lien vers une explication) pourquoi
java.io.File
est un exemple intéressant? File
est intéressant parce qu'il est susceptible de faire confiance à un être immuable, et donc conduire à TOCTOU (Moment De l'enregistrement/au Moment De l'Utilisation) des attaques. Le code de confiance vérifie que leFile
un chemin d'accès, puis utilise le chemin d'accès. Un sous-classéFile
peut changer de valeur entre les vérifier et de les utiliser.
Vous devez vous connecter pour publier un commentaire.
Si vous ne cochez pas la classe
final
, il pourrait être possible pour moi d'un coup à faire de votre apparence immuable classe mutable. Considérons par exemple ce code:Maintenant, supposons que je ne les suivants:
Avis que, dans mon
Mutable
sous-classe, j'ai surchargé le comportement degetValue
lire une nouvelle, mutable champ déclarée dans mon sous-classe. En conséquence, votre classe, qui au départ semble immuable, n'est vraiment pas immuable. Je peux passer ceMutable
objet dans uneImmutable
objet est prévu, ce qui pourrait faire Très Mal de Choses à code en supposant que l'objet est vraiment immuable. Le marquage de la classe de basefinal
empêche que cela se produise.Espérons que cette aide!
Immutable
un argument. Je peux passer unMutable
objet de cette fonction, depuisMutable extends Immutable
. À l'intérieur de cette fonction, alors que vous pensez que votre objet est immuable, je pourrais avoir un thread secondaire qui passe et les changements de la valeur que la fonction s'exécute. Je pourrais aussi vous donner unMutable
objet que la fonction de magasins, puis plus tard de modifier sa valeur à l'extérieur. En d'autres termes, si votre fonction prend la valeur est immuable, il pourrait facilement se casser, car je pourrais vous donner un objet mutable et le changer plus tard. Cela fait-il sens?Mutable
objet ne va pas changer l'objet. Le souci est que cette méthode pourrait supposer que l'objet est immuable quand il ne l'est pas vraiment. Par exemple, la méthode pourrait supposer que, depuis, il pense que l'objet est immuable, il peut être utilisé comme clé dans uneHashMap
. Je ne puis rompre cette fonction en passant dans unMutable
, en attente pour le stockage de l'objet comme une clé, puis en modifiant laMutable
objet. Maintenant, les recherches dans ceHashMap
sera un échec, car j'ai changé la clé associée à l'objet. Cela fait-il sens?HashMap
exemple, lahashCode
méthode devra êtrefinal
ainsi, et rien d'autre hérité deObject
qui pourrait avoir un impact, qui est la raison pour laquelle la classefinal
est beaucoup plus simple.private final
membres est assez d'une barrière dans la plupart des cas. J'ai appelé les autres (souvent invisible) des méthodes qui m'ont piqué dans le passé, commehashCode
de sorte qu'ils n'ont pas été oubliés 😉private final
il sera toujours en mesure de mettre à jour dans la même classe donc la rupture immuable...corrigez-moi si je suis mal.Immutable immObj = (Immutable)obj;
- immuable de la classe VHR pointe vers un objet mutable, et il peut le faire parce que c'est super classe. Le Point ici est que l'objet est de mutable classe et pas immuable de la classe, si vous créez l'objet de immuable classe alors il serait toujours immuable.Immutable
, vous ne pouvez pas dire si c'est en se référant à un réel, honnête à la bontéImmutable
objet ou si elle pointe vers un délicatMutable
objet qui peut réellement changer au fil du temps. Le casting est ici parfaitement sûr, mais cache le fait qu'un objet de référence qui indique que l'objet ne changera jamais réellement points pour quelque chose qui peut vraiment changer au fil du temps.Contrairement à ce que pensent beaucoup de personnes, faire un immuable classe
final
est pas nécessaire.La norme argument pour rendre immuable classes
final
est que si vous ne le faites pas, alors les sous-classes peuvent ajouter de la mutabilité, violant le contrat de la super-classe. Les Clients de la classe d'assumer l'immuabilité, mais seront surpris quand quelque chose se transforme sous eux.Si vous prenez cet argument à sa logique extrême, puis tous méthodes
final
, sinon une sous-classe peut remplacer une méthode dans un sens qui ne sont pas conformes au contrat de sa super-classe. Il est intéressant de noter que la plupart des programmeurs Java voir ce que ridicule, mais sont en quelque sorte d'accord avec l'idée que l'immuable classes doivent êtrefinal
. Je suppose que cela a quelque chose à faire avec des programmeurs Java en général pas totalement à l'aise avec la notion de l'immuabilité, et peut-être une sorte de flou réflexion sur les multiples sens de lafinal
mot-clé dans Java.Conforme au contrat de votre super-classe n'est pas quelque chose qui peut ou doit toujours être appliqué par le compilateur. Le compilateur peut appliquer certains aspects de votre contrat (par exemple: au moins un ensemble de méthodes et de leur type de signatures), mais il ya de nombreuses parties de contrats atypiques qui ne peut être exécutée par le compilateur.
Immutabilité est une partie du contrat d'une classe. C'est un peu différente de certaines des choses que les gens sont plus, parce qu'il dit ce que la classe (et toutes les sous-classes) ne peut pas faire, alors que je pense que la plupart de Java (et plus généralement de la POO) les programmeurs ont tendance à penser à des contrats relatifs à la signification d'une classe peut faire, pas ce qu'il ne peut pas faire.
Immutabilité affecte également plus qu'une unique méthode qu'il affecte l'ensemble de l'instance — mais ce n'est pas vraiment très différent de la façon dont
equals
ethashCode
en Java de travail. Ces deux méthodes ont un contrat spécifique énoncée dansObject
. Ce contrat très attentivement dispose de choses que ces méthodes ne peut pas faire. Ce contrat est fait plus précis dans les sous-classes. Il est très facile de remplacerequals
ouhashCode
d'une manière qui constitue une violation du contrat. En fait, si vous remplacez un seul de ces deux méthodes sans l'autre, les chances sont que vous êtes violation du contrat. Devrait doncequals
ethashCode
ont été déclaréesfinal
dansObject
pour éviter cela? Je pense que la plupart diront qu'ils ne devraient pas. De même, il n'est pas nécessaire pour rendre immuable classesfinal
.Cela dit, la plupart de vos classes, immuable ou pas, probablement devrait être
final
. Voir Efficace Java Deuxième Édition Article 17: "la Conception et le document de l'héritage ou de l'autre de l'interdire".Donc une version correcte de votre étape 3 serait: "Faire la classe finale ou lors de la conception de sous-classement, de documenter clairement que toutes les sous-classes doivent continuer à être immuable."
X
etY
, la valeur deX.equals(Y)
sera immuable (tant queX
etY
continuer à se référer aux mêmes objets). Elle a les mêmes attentes concernant les codes de hachage. Il est clair que personne ne devrait s'attendre au compilateur de faire respecter l'immutabilité des relations d'équivalence et des codes de hachage (car il tout simplement ne peut pas faire). Je ne vois aucune raison pour laquelle les gens devraient s'attendre à être appliquées à d'autres aspects d'un type.double
. On pourrait en déduire uneGeneralImmutableMatrix
qui utilise un tableau comme un magasin de sauvegarde, mais on peut également, comme par exemple leImmutableDiagonalMatrix
qui stocke tout simplement un tableau d'éléments le long de la diagonale (la lecture de l'élément X,Y donnerait Arr[X] si X==y et zéro sinon).final
limite son utilité, en particulier lors de la conception d'une API destinée à être étendue. Dans l'intérêt de fil de sécurité, il est logique de faire de votre classe aussi immuables que possible, mais le garder extensible. Vous pouvez faire les champsprotected final
au lieu deprivate final
. Puis, de manière explicite à l'établissement d'un contrat (dans la documentation) sur des sous-classes en adhérant à l'immutabilité et enfilez-les garanties de sécurité.Ne marque pas l'ensemble de la classe finale.
Il y a des raisons valables pour permettre aux est immuable de la classe à être étendu comme indiqué dans les autres réponses afin de marquage de la classe comme final n'est pas toujours une bonne idée.
C'est mieux pour marquer vos biens privés et finale, et si vous voulez protéger le "contrat" marque de votre getters comme définitive.
De cette façon, vous pouvez autoriser la classe d'être étendu (oui peut-être même par une mutable classe) cependant les aspects immuables de votre classe sont protégés. Les propriétés sont privées et ne peuvent pas être accessibles, des getters pour ces propriétés sont définitives et ne peuvent pas être remplacées.
Tout autre code qui utilise une instance de votre immuables de la classe sera en mesure de compter sur les aspects immuables de votre classe, même si la sous-classe, il est transmis est mutable dans d'autres aspects. Bien sûr, puisqu'il faut une instance de votre classe, il ne voulait même pas connaître l'existence de ces autres aspects.
Si elle n'est pas finale, puis quelqu'un pourrait étendre la classe et de faire ce qu'ils souhaitent, comme la fourniture de setters, l'occultation de votre variables privées, et, essentiellement, le rendant mutable.
Que les contraintes des autres classes de l'extension de votre classe.
finale de la classe ne peut pas être prolongé par d'autres classes.
Si une classe d'étendre la classe que vous voulez faire comme immuable, il peut changer l'état de la classe en raison de l'héritage de principes.
Juste préciser "il peut changer". Sous-classe peut remplacer superclasse genre de comportement à l'aide de la redéfinition de méthode (comme templatetypedef/Ted Hop réponse)
final
, je ne vois pas comment cette réponse aide.Pour la création immuable de la classe, il n'est pas obligatoire de marquer la classe finale.
Permettez-moi de prendre un tel exemple à partir des classes java lui-même "BigInteger" la classe est immuable, mais ce n'est pas définitive.
Fait l'Immuabilité est un concept selon lesquelles l'objet créé alors il ne peut pas être modifié.
Nous allons réfléchir à partir de la JVM point de vue, à partir de la JVM point de vue de tous les threads doivent partager la même copie de l'objet et il est entièrement construit avant n'importe quel thread accède à celle-ci et l'état de l'objet ne change pas après sa construction.
Immutabilité signifie qu'il n'existe aucun moyen yo changement de l'état de l'objet une fois qu'il est créé et ce qui est réalisé par les trois règles qui en fait le compilateur de reconnaître que la classe est immuable et ils sont comme suit :-
Pour plus d'informations, reportez-vous à l'URL ci-dessous
http://javaunturnedtopics.blogspot.in/2016/07/can-we-create-immutable-class-without.html
Si vous ne le faites pas final je peux l'étendre et de le rendre non mutable.
Maintenant, je peux passer FakeImmutable à toute la classe qui attend Immuable, et il ne se comportera pas comme le contrat prévu.
Supposons que la classe suivante n'étaient pas
final
:C'est apparemment immuable, parce que même les sous-classes ne pouvez pas modifier
mThing
. Cependant, une sous-classe peut être mutables:Maintenant un objet qui est assignable à une variable de type
Foo
n'est plus garanti pour être mmutable. Cela peut causer des problèmes avec des choses comme le hachage, l'égalité, la concurrence, etc.La conception en elle-même n'a aucune valeur. Le Design est toujours utilisé pour atteindre un but. Quel est le but ici? Nous ne voulons réduire la quantité de surprises dans le code? Voulons-nous éviter les bugs? Sommes-nous en suivant aveuglément les règles?
Aussi, le design a un coût. Chaque conception qui mérite ce nom signifie que vous avez un conflit d'objectifs.
Avec cela à l'esprit, vous avez besoin de trouver des réponses à ces questions:
Dire que vous avez beaucoup de junior les développeurs de votre équipe. Ils tentent désespérément de toute chose stupide juste parce qu'ils ne savent pas de bonnes solutions à leurs problèmes, encore. Faire de la classe finale pourrait empêcher les insectes (bon), mais pourrait aussi les faire venir avec "intelligent" des solutions telles que la copie de l'ensemble de ces classes dans une mutable partout dans le code.
D'autre part, il sera très difficile de faire une classe
final
après il est utilisé partout, mais il est facile de faire unfinal
classe non-final
plus tard si vous trouvez que vous avez besoin de le prolonger.Si vous utilisez correctement les interfaces, vous pouvez éviter le "j'ai besoin de faire ce mutable" problème en utilisant toujours l'interface, puis, plus tard, l'ajout d'une mutable mise en œuvre lorsque le besoin s'en fait sentir.
Conclusion: Il n'y a pas de "meilleure" solution pour répondre à cette question. Cela dépend du prix que vous êtes prêt et que vous avez à payer.
Le défaut de sens de equals() est le même que le référentiel de l'égalité. Pour immuable types de données, ce qui est presque toujours mauvais. Donc, vous avez à redéfinir la méthode equals (), pour le remplacer par votre propre mise en œuvre. lien