Nous savons tous que `` est immuable en Java, mais vérifier le code suivant :
Pourquoi ce programme ne fonctionne pas comme ça ? Et pourquoi la valeur de et
a changé, mais ne pas `` ?
Nous savons tous que `` est immuable en Java, mais vérifier le code suivant :
Pourquoi ce programme ne fonctionne pas comme ça ? Et pourquoi la valeur de et
a changé, mais ne pas `` ?
String
est immuable* mais cela ne signifie que vous ne pouvez pas le changer en utilisant son API publique.
Ce que vous faites ici est de contourner la normale de l'API, à l'aide de la réflexion. De la même manière, vous pouvez modifier les valeurs d'énumérations, de modifier la table de recherche utilisé en Entier l'autoboxing etc.
Maintenant, la raison en s1
et s2
la valeur de changement, c'est qu'ils se réfèrent à la même interné chaîne. Le compilateur est-ce (comme mentionné par d'autres réponses).
La raison en s3
n'a pas était en fait un peu surprenant pour moi, comme je l'ai pensé qu'il serait part de l' value
tableau (il l'a fait dans la version antérieure de Java, avant de Java 7u6). Cependant, en regardant le code source de l' String
, nous pouvons voir que l' value
tableau de caractères d'une chaîne est effectivement copiés (à l'aide d' Arrays.copyOfRange(..)
). C'est pourquoi il n'est pas modifié.
Vous pouvez installer un SecurityManager
, pour éviter de code malveillant à faire de telles choses. Mais gardez à l'esprit que certaines bibliothèques dépendent de l'utilisation de ces sortes de réflexions astuces (généralement, outils ORM, AOP bibliothèques, etc).
*) J'ai d'abord écrit qu' String
s ne sont pas vraiment immuable, juste "efficace immuable". Cela peut être trompeur dans la mise en œuvre actuelle de l' String
, où l' value
tableau est en effet marquée private final
. Il est encore intéressant de noter, cependant, qu'il n'est pas possible de déclarer un tableau en Java comme immuable, donc il faut prendre soin de ne pas l'exposer à l'extérieur de sa classe, même avec le bon modificateurs d'accès.
Comme ce sujet semble massivement populaire, voici quelques suggestions de lectures complémentaires: Heinz Kabutz la Réflexion de la Folie de parler de JavaZone 2009, qui couvre beaucoup de questions dans l'OP, le long de avec d'autres de la réflexion... eh bien... la folie.
Il couvre pourquoi ce qui est parfois utile. Et pourquoi, la plupart du temps, vous devriez éviter. :-)
En Java, si deux chaînes de caractères primitifs variable initialisée par la même littéral ils ont attribué la même référence à deux variables:
String Test1="Hello World";
String Test2="Hello World";
System.out.println(test1==test2); // true
c'est la raison pour comparaison renvoie la valeur true. Troisième chaîne créée à l'aide de substring()
qui en font une nouvelle chaîne au lieu de pointer le même.
lorsque vous accédez à l'aide de la chaîne de la réflexion, Vous obtenez le réel pointeur:
Field field = String.class.getDeclaredField("value");
field.setAccessible(true);
Ainsi le changement de ce qui va changer la chaîne de caractères contenant le pointeur de lui, mais que s3 est créé une nouvelle chaîne en raison d' substring()
il ne changerait pas.
Vous êtes à l'aide de la réflexion afin de contourner l'immutabilité de la Chaîne - c'est une forme d ' "attaque".
Il y a beaucoup d'exemples que vous pouvez créer comme ceci (par exemple, vous pouvez même instancier un Void
objet de trop), mais ça ne veut pas dire que la Chaîne n'est pas "immuable".
Il y a des cas d'utilisation où ce type de code peut être utilisé à votre avantage et être "bon codage", comme l' effacement des mots de passe à partir de la mémoire le plus tôt possible (avant le GC).
Selon le directeur de la sécurité, vous ne pouvez pas être en mesure d'exécuter votre code.
Modificateurs de visibilité et final (c'est à dire l'immuabilité) ne sont pas une mesure contre les codes malveillants en Java; ils sont simplement des outils pour se protéger contre les erreurs et pour rendre le code plus facile à maintenir (un des gros points de vente du système). C'est pourquoi vous pouvez accéder à la mise en œuvre interne des détails comme la sauvegarde de char tableau pour String
s grâce à la réflexion.
Le deuxième effet de vous voir, c'est que tous String
s changer bien qu'il semble que vous n'variation s1
. C'est une certaine propriété de Java littéraux de Chaîne qu'ils sont automatiquement interné, c'est à dire mis en cache. Deux littéraux de Chaîne avec la même valeur sera effectivement le même objet. Lorsque vous créez une Chaîne avec des new
il ne sera pas interné, automatiquement et vous ne verrez pas cet effet.
#substring
jusqu'à récemment (Java 7u6) a travaillé d'une manière similaire, ce qui aurait expliqué le comportement de la version d'origine de votre question. Il n'a pas créer une nouvelle sauvegarde de char tableau mais réutilisés celui de la Chaîne d'origine; qu'il vient de créer un nouvel objet String qui ont utilisé un offset et une longueur à l'heure actuelle, seule une partie de ce tableau. Généralement, il a travaillé comme des Chaînes de caractères sont immuables, à moins de contourner cela. Cette propriété de #substring
signifie également que l'ensemble de la Chaîne d'origine ne pouvait pas être nettoyée lorsqu'une plus courte chaîne créée à partir d'elle existait encore.
Comme actuelles de Java et de votre version actuelle de la question, il n'est pas étrange comportement de l' #substring
.
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.