145 votes

Pourquoi la classe String est-elle déclarée finale en Java ?

A partir du moment où j'ai appris que la classe java.lang.String est déclaré comme final en Java, je me demandais pourquoi. Je n'ai pas trouvé de réponse à l'époque, mais ce post : Comment créer une réplique de la classe String en Java ? m'a rappelé ma requête.

Bien sûr, String fournit toutes les fonctionnalités dont j'ai toujours eu besoin, et je n'ai jamais pensé à une opération qui nécessiterait une extension de la classe String, mais on ne sait jamais ce dont quelqu'un pourrait avoir besoin !

Alors, quelqu'un sait-il quelle était l'intention des concepteurs lorsqu'ils ont décidé de la rendre définitive ?

0 votes

Merci à tous pour vos réponses, en particulier à TrueWill, Bruno Reis et Thilo ! J'aimerais pouvoir choisir plus d'une réponse comme étant la meilleure, mais malheureusement... !

1 votes

Considérez également la prolifération de projets "Oh, j'ai juste besoin de quelques méthodes utilitaires supplémentaires sur String" qui apparaîtraient - tous ne pourraient pas utiliser les Strings des autres parce qu'ils sont d'une classe différente.

0 votes

Merci pour cette réponse très utile. Nous avons deux faits maintenant. Une chaîne est une classe finale et est immuable parce qu'elle ne peut pas être changée mais peut être référencée à un autre objet. Mais qu'en est-il de : String a = new String("test1") ; then, s = "test2" ; Si String est un objet de classe finale alors comment peut-il être modifié ? Comment puis-je utiliser un objet final modifié ? S'il vous plaît laissez-moi si j'ai mal demandé quelque chose.

90voto

Bruno Reis Points 16132

Il est très utile d'avoir des chaînes de caractères implémentées en tant que objets immuables . Vous devez vous renseigner sur immuabilité pour en savoir plus.

Un avantage de objets immuables c'est que

Vous pouvez partager les doublons en les faisant pointer vers une seule instance.

(de aquí ).

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 Strings", mais qui sont en fait différentes.

76 votes

A moins qu'il y ait un lien entre les classes finales et les objets immuables que je ne vois pas, je ne vois pas en quoi votre réponse est liée à la question.

9 votes

Parce que s'il n'est pas final, vous pouvez passer un StringChild à une méthode en tant que paramètre String, et il pourrait être mutable (parce que l'état d'une classe enfant change).

0 votes

Empêcher les sous-classes empêche une sous-classe mutable.

59voto

Anurag Points 66470

C'est un bon article qui expose les deux raisons déjà mentionnées dans les réponses ci-dessus :

  1. Sécurité : le système peut distribuer d'informations sensibles en lecture seule sans craindre que qu'elles soient modifiées
  2. Performance Les données immuables sont très utile pour rendre les choses sûres pour les fils.

Et c'est probablement le commentaire le plus détaillé de cet article. Il concerne le pool de chaînes de caractères en Java et les questions de sécurité. Il s'agit de savoir comment décider ce qui va dans le pool de chaînes. En supposant que les deux chaînes sont égales si leur séquence de caractères est la même, nous avons alors une condition de course sur qui arrive en premier et avec cela des problèmes de sécurité. Si ce n'est pas le cas, le pool de chaînes de caractères contiendra des chaînes redondantes, perdant ainsi l'avantage de l'avoir en premier lieu. Lisez-le vous-même, voulez-vous ?


L'extension de la chaîne de caractères perturberait les égaux et les internes. JavaDoc dit equals :

Compare cette chaîne à l'objet spécifié. Le résultat est vrai si et seulement si l'argument n'est pas nul et est un objet String qui représente la même séquence de caractères que cet objet.

En supposant que java.lang.String n'était pas définitif, un SafeString pourrait correspondre à un String et vice versa, car ils représentent la même séquence de caractères.

Que se passerait-il si vous appliquiez intern à un SafeString -- est-ce que le SafeString dans le pool de chaînes de la JVM ? Le site ClassLoader et tous les objets que le SafeString détenait des références serait alors verrouillé en place pour la durée de vie de la JVM. On obtiendrait une condition de course pour savoir qui serait le premier à internaliser une séquence de caractères -- peut-être que votre SafeString gagnerait, peut-être un String ou peut-être un SafeString chargé par un classloader différent (donc une classe différente).

Si vous gagnez la course à la piscine, il s'agirait d'un véritable singleton et les gens pourraient accéder à l'ensemble de votre environnement (bac à sable) par le biais de la réflexion et de la fonction secretKey.intern().getClass().getClassLoader() .

La JVM pourrait aussi bloquer ce trou en s'assurant que seuls des objets String concrets (et aucune sous-classe) sont ajoutés au pool.

Si les égaux étaient mis en œuvre de telle sorte que SafeString != String puis SafeString.intern != String.intern y SafeString devrait être ajouté à la réserve. La réserve deviendrait alors une réserve de <Class, String> au lieu de <String> et tout ce dont vous auriez besoin pour entrer dans la piscine serait un nouveau chargeur de classe.

3 votes

Bien sûr, l'argument des performances est fallacieux : si String avait été une interface, j'aurais pu fournir une implémentation plus performante dans mon application.

27voto

Jackob Points 411

La raison absolument la plus importante pour laquelle String est immuable ou final est qu'il est utilisé par le mécanisme de chargement des classes, et a donc des aspects de sécurité profonds et fondamentaux.

Si String avait été mutable ou non final, une demande de chargement de "java.io.Writer" aurait pu être modifiée pour charger "mil.vogoon.DiskErasingWriter".

référence : Pourquoi String est immuable en Java

16voto

Thilo Points 108673

String est une classe très importante en Java, de nombreuses choses dépendent de son fonctionnement, par exemple son caractère immuable.

Faire la classe final empêche les sous-classes qui pourraient briser ces hypothèses.

Notez que, même maintenant, si vous utilisez la réflexion, vous pouvez casser les cordes (changer leur valeur ou leur code de hachage). Reflection peut être arrêté par un gestionnaire de sécurité. Si String n'était pas final tout le monde pouvait le faire.

Autres classes qui ne sont pas déclarées final vous permettent de définir des sous-classes quelque peu brisées (vous pourriez avoir une List qui ajoute à la mauvaise position, par exemple), mais au moins la JVM ne dépend pas de ces éléments pour ses opérations de base.

6 votes

final sur une classe ne garantit pas l'immuabilité. Elle 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.

2 votes

@Kevin : oui. Final sur une classe garantit qu'il n'y a pas de sous-classes. Cela n'a rien à voir avec l'immuabilité.

4 votes

Le fait de rendre une classe finale ne la rend pas, en soi, immuable. Mais rendre une classe immuable finale assure que personne ne crée une sous-classe qui rompt l'immuabilité. Peut-être que les personnes qui ont fait la remarque sur l'immuabilité n'étaient pas claires sur ce qu'elles voulaient dire exactement, mais leurs déclarations sont correctes lorsqu'elles sont comprises dans leur contexte.

6voto

Artur Points 1271

Comme l'a dit Bruno, il s'agit d'immuabilité. Il ne s'agit pas seulement des chaînes de caractères, mais aussi de tous les wrappers, tels que les doubles, les entiers, les caractères, etc. Il y a de nombreuses raisons à cela :

  • Sécurité du fil
  • Sécurité
  • Le tas est géré par Java lui-même (différemment du tas ordinaire qui est collecté de manière différente).
  • Gestion de la mémoire

En fait, cela vous permet, en tant que programmeur, d'être sûr que votre chaîne ne sera jamais modifiée. De plus, si vous savez comment cela fonctionne, cela 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 "hello". Vous remarquerez, si vous déboguez, qu'elles ont des ID identiques, ce qui signifie que ce sont exactement LES MÊMES objets. Ceci est dû au fait que Java vous permet de le faire. Cela ne serait pas possible si les chaînes de caractères étaient mutables. Elles peuvent avoir les mêmes I'd, etc., car elles ne changeront jamais. Ainsi, si vous décidez de créer 1 000 000 de chaînes "hello", vous créerez en réalité 1 000 000 de pointeurs vers "hello". De même, l'utilisation de toute fonction sur une chaîne de caractères, ou de tout wrapper pour cette raison, entraînerait la création d'un autre objet (regardez à nouveau l'ID de l'objet - il changera).

De plus, final en Java ne signifie pas nécessairement signifie que l'objet ne peut pas changer (c'est différent de C++ par exemple). Cela signifie que l'adresse vers laquelle il pointe ne peut pas changer, mais que vous pouvez toujours modifier ses propriétés et/ou attributs. Il peut donc être très important de comprendre la différence entre immuabilité et finalité dans certains cas.

HTH

Références :

1 votes

Je ne pense pas que les chaînes soient placées dans un tas différent ou qu'elles utilisent une gestion différente de la mémoire. Elles sont certainement récupérables par les ordures.

2 votes

En outre, le mot-clé final d'une classe est complètement différent du mot-clé final d'un champ.

1 votes

D'accord, sur la JVM de Sun, les chaînes de caractères qui sont intern()ées peuvent aller dans le perm-gen, qui ne fait pas partie du tas. Mais cela ne se produit certainement pas pour toutes les chaînes de caractères, ni pour toutes les JVM.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X