À partir du moment où j'ai appris que la classe java.lang.String
est déclarée comme finale en Java, je me demandais pourquoi. Je n'ai trouvé aucune réponse à l'époque, mais cet article: Comment créer une réplique de la classe String en Java?m'a rappelé ma question.
Bien sûr, String fournit toutes les fonctionnalités dont j'ai jamais eu besoin, et je n'ai jamais pensé à une opération qui nécessiterait une extension de la classe String, mais vous ne saurez toujours jamais ce dont quelqu'un pourrait avoir besoin!
Alors, est-ce que quelqu'un sait quelle était l'intention des concepteurs lorsqu'ils ont décidé de le rendre définitif?
Réponses:
Il est très utile d'avoir des chaînes implémentées en tant qu'objets immuables . Vous devriez lire sur l' immuabilité pour en savoir plus.
L'un des avantages des objets immuables est que
(d' ici ).
Si String n'était pas final, vous pourriez créer une sous-classe et avoir deux chaînes qui se ressemblent lorsqu'elles sont "vues comme des chaînes", mais qui sont en fait différentes.
la source
C'est un bel article qui décrit deux raisons déjà mentionnées sur les réponses ci-dessus:
Et c'est probablement le commentaire le plus détaillé de cet article. Cela a à voir avec le pool de chaînes en Java et les problèmes de sécurité. Il s'agit de savoir comment décider de ce qui entre dans le pool de cordes. En supposant que les deux chaînes sont égales si leur séquence de caractères est la même, alors nous avons une condition de concurrence sur qui y arrive en premier et avec des problèmes de sécurité. Sinon, le pool de chaînes contiendra des chaînes redondantes, perdant ainsi l'avantage de l'avoir en premier lieu. Lisez-le par vous-même, d'accord?
L'extension de String ferait des ravages avec les égaux et les stagiaires. JavaDoc dit égal:
En supposant que ce
java.lang.String
n'était pas définitif, aSafeString
pourrait égaler aString
, et vice versa; parce qu'ils représenteraient la même séquence de caractères.Que se passerait-il si vous postuliez
intern
à unSafeString
- iraitSafeString
-il dans le pool de chaînes de la JVM? LesClassLoader
objets et tous les objets auxquels lesSafeString
références sont conservées seraient alors verrouillés pendant toute la durée de vie de la machine virtuelle Java. Vous obtiendrez une condition de concurrence sur qui pourrait être le premier à interner une séquence de personnages - peut-être que vousSafeString
gagneriez, peut-être unString
, ou peut-être unSafeString
chargé par un chargeur de classe différent (donc une classe différente).Si vous gagniez la course dans la piscine, ce serait un vrai singleton et les gens pourraient accéder à l'ensemble de votre environnement (bac à sable) par réflexion et
secretKey.intern().getClass().getClassLoader()
.Ou la JVM pourrait bloquer ce trou en s'assurant que seuls des objets String concrets (et aucune sous-classe) étaient ajoutés au pool.
Si égal a été implémenté de telle sorte que
SafeString
! =String
AlorsSafeString.intern
! =String.intern
, EtSafeString
devrait être ajouté au pool. La piscine deviendrait alors une piscine<Class, String>
au lieu de<String>
et tout ce dont vous auriez besoin pour entrer dans le pool serait un nouveau chargeur de classe.la source
La raison absolument la plus importante pour laquelle String est immuable ou définitif est qu'il est utilisé par le mécanisme de chargement de classe, et a donc des aspects de sécurité profonds et fondamentaux.
Si String avait été mutable ou non définitif, une demande de chargement de "java.io.Writer" aurait pu être modifiée pour charger "mil.vogoon.DiskErasingWriter"
reference: Pourquoi String est immuable en Java
la source
String
est une classe très fondamentale en Java, beaucoup de choses dépendent de son fonctionnement d'une certaine manière, par exemple étant immuable.Faire la classe
final
empêche les sous-classes qui pourraient casser ces hypothèses.Notez que, même maintenant, si vous utilisez la réflexion, vous pouvez casser les chaînes (modifier leur valeur ou leur hashcode). La réflexion peut être arrêtée avec un gestionnaire de sécurité. Si ce
String
n'était pasfinal
, tout le monde pouvait le faire.D'autres classes qui ne sont pas déclarées
final
vous permettent de définir des sous-classes quelque peu cassées (vous pourriez avoir unList
qui s'ajoute à la mauvaise position, par exemple) mais au moins la JVM ne dépend pas de celles-ci pour ses opérations de base.la source
final
sur une classe ne garantit pas l'immuabilité. Cela garantit simplement que les invariants d'une classe (dont l'un peut être l'immuabilité) ne peuvent pas être modifiés par une sous-classe.Comme l'a dit Bruno, il s'agit d'immuabilité. Il ne s'agit pas seulement de chaînes de caractères, mais aussi de tout wrapper, par exemple Double, Integer, Character, etc. Il y a plusieurs raisons à cela:
En gros, cela vous permet, en tant que programmeur, d'être sûr que votre chaîne ne sera jamais modifiée. Cela aussi, si vous savez comment cela fonctionne, peut améliorer la gestion de la mémoire. Essayez de créer deux chaînes identiques l'une après l'autre, par exemple "bonjour". Vous remarquerez, si vous déboguez, qu'ils ont des ID identiques, cela signifie qu'ils sont exactement LES MÊMES objets. Cela est dû au fait que Java vous permet de le faire. Ce ne serait pas possible si les chaînes étaient muttables. Ils peuvent avoir la même chose que moi, etc., car ils ne changeront jamais. Donc, si jamais vous décidez de créer 1 000 000 chaînes "bonjour", ce que vous feriez vraiment est de créer 1 000 000 pointeurs vers "bonjour". De plus, allouer n'importe quelle fonction sur une chaîne, ou n'importe quel wrapper pour cette raison, entraînerait la création d'un autre objet (regardez à nouveau l'ID de l'objet - cela changera).
De plus, la finale en Java n'est pas nécessairement signifie que l'objet ne peut pas changer (il est différent par exemple de C ++). Cela signifie que l'adresse vers laquelle il pointe ne peut pas changer, mais vous pouvez toujours modifier ses propriétés et / ou ses attributs. Donc, comprendre la différence entre l'immuabilité et le final dans certains cas peut être vraiment important.
HTH
Références:
la source
C'était peut-être pour simplifier la mise en œuvre. Si vous concevez une classe qui sera héritable par les utilisateurs de la classe, vous avez alors un tout nouvel ensemble de cas d'utilisation à prendre en compte dans votre conception. Que se passe-t-il s'ils font ceci ou cela avec le champ X protégé? En le rendant définitif, ils peuvent se concentrer sur le bon fonctionnement de l'interface publique et s'assurer qu'elle est solide.
la source
Avec beaucoup de bons points déjà mentionnés, j'aimerais en ajouter un autre - l'une des raisons pour lesquelles String est immuable en Java est de permettre à String de mettre en cache son hashcode , étant immuable String en Java met en cache son hashcode, et ne calcule pas tous heure à laquelle nous appelons la méthode hashcode de String , ce qui la rend très rapide en tant que clé hashmap à utiliser dans hashmap en Java.
En bref, étant donné que String est immuable, personne ne peut modifier son contenu une fois créé, ce qui garantit que le hashCode de String sera le même lors d'appels multiples.
Si vous voyez que la
String
classe a est déclarée commeet la
hashcode()
fonction est la suivante -S'il s'agit déjà d'un ordinateur, renvoyez simplement la valeur.
la source
Pour nous assurer que nous n'obtenons pas une meilleure mise en œuvre. Cela aurait bien sûr dû être une interface.
[modifier] Ah, obtenir des votes plus ignorants. La réponse est parfaitement sérieuse. J'ai dû programmer plusieurs fois mon chemin autour de l'implémentation stupide de String, entraînant une perte de performances et de productivité sévère
la source
Outre les raisons évidentes suggérées dans d'autres réponses, l'idée de rendre la classe String finale pourrait également être liée à la surcharge de performance des méthodes virtuelles. N'oubliez pas que String est une classe lourde, ce qui rend cette finale, signifie pas de sous-implémentation à coup sûr, signifie pas de surcharge d'appel d'indirection. Bien sûr, nous avons maintenant des choses comme l'invocation virtuelle et d'autres, qui font toujours ce type d'optimisation pour vous.
la source
En plus des raisons mentionnées dans d'autres réponses (sécurité, immuabilité, performances), il convient de noter qu'il
String
dispose d'un support linguistique spécial. Vous pouvez écrire desString
littéraux et il existe un support pour l'+
opérateur. Permettre aux programmeurs de se sousString
-classer encouragerait les hacks tels que:la source
Eh bien, j'ai une pensée différente, je ne sais pas si j'ai raison ou non, mais en Java, la chaîne est le seul objet qui peut être traité comme un type de données primitif, je veux dire que nous pouvons créer un objet String comme String name = "java " . Maintenant, comme d'autres types de données primitifs qui sont copiés par valeur et non par référence, String devrait avoir le même comportement, c'est pourquoi String est final. C'est ce que je pensais. Veuillez ignorer si c'est complètement illogique.
la source
La finalité des cordes les défend également comme un standard. En C ++, vous pouvez créer des sous-classes de string, de sorte que chaque boutique de programmation puisse avoir sa propre version de string. Cela conduirait à un manque de norme solide.
la source
Disons que vous avez une
Employee
classe qui a une méthodegreet
. Lorsque lagreet
méthode est appelée, elle s'imprime simplementHello everyone!
. Voilà donc le comportement attendu de lagreet
méthodeMaintenant, laissez la
GrumpyEmployee
sous - classeEmployee
et lagreet
méthode de substitution comme indiqué ci-dessous.Maintenant, dans le code ci-dessous, jetez un œil à la
sayHello
méthode. Il prend uneEmployee
instance comme paramètre et appelle la méthode greet en espérant qu'il diraitHello everyone!
Mais ce que nous obtenons estGet lost!
. Ce changement de comportement est dû àEmployee grumpyEmployee = new GrumpyEmployee();
Cette situation peut être évitée si le
Employee
cours a été faitfinal
. Maintenant, c'est à votre imagination la quantité de chaos qu'un programmeur effronté pourrait causer siString
Class n'était pas déclaré commefinal
.la source
JVM sait-il ce qui est immuable? La réponse est non, le pool de constantes contient tous les champs immuables mais tous les champs / objets immuables ne sont pas stockés uniquement dans le pool de constantes. Seulement, nous l'implémentons de manière à atteindre l'immuabilité et ses caractéristiques. CustomString pourrait être implémenté sans le rendre définitif en utilisant MarkerInterface qui fournirait un comportement spécial java pour son pooling, la fonctionnalité est toujours attendue!
la source
La plupart des réponses sont liées à l'immuabilité - pourquoi un objet de type String ne peut pas être mis à jour sur place. Il y a beaucoup de bonnes discussions ici, et la communauté Java ferait bien d'adopter l'immuabilité comme principe. (Ne retenant pas mon souffle.)
Cependant, la question du PO est de savoir pourquoi il est définitif - pourquoi ne peut-il pas être prolongé. Certains ici l'ont fait, mais je suis d'accord avec le PO pour dire qu'il y a un réel écart ici. Un autre langage permet aux développeurs de créer de nouveaux types nominaux pour un type. Par exemple, dans Haskell, je peux créer les nouveaux types suivants qui sont identiques au moment de l'exécution en tant que texte, mais fournissent la sécurité de liaison au moment de la compilation.
Je proposerais donc la suggestion suivante comme une amélioration du langage Java:
(Ou peut-être pourrions-nous commencer à nous déconnecter de Java)
la source
Si vous créez une chaîne une seule fois, il considérera que, c'est un objet si vous voulez modifier cela, ce n'est pas possible, cela créera un nouvel objet.
la source