Concernant les questions de cette série, tous ceux qui étudient Java devraient les comprendre. Bien sûr, peu importe si vous apprenez Java simplement pour le plaisir. Si vous pensez avoir dépassé le niveau débutant mais que vous ne comprenez pas bien ces problématiques, merci de vous ajouter à l’équipe débutant.
Question 1 : Qu’est-ce que je dis ?
String s = "Bonjour tout le monde !";
Beaucoup de gens l'ont fait, mais que déclarons-nous exactement ? La réponse est généralement : une chaîne avec le contenu « Hello world ! ». Ces réponses vagues sont souvent à l’origine de concepts peu clairs. Si vous deviez donner une réponse précise, probablement la moitié des personnes répondraient mal.
Cette instruction déclare une référence à un objet, nommé "s", qui peut pointer vers n'importe quel objet de type String. Actuellement, elle pointe vers l'objet de type String "Hello world!". C'est ce qui s'est réellement passé. Nous n'avons pas déclaré d'objet String, nous avons simplement déclaré une variable de référence qui ne peut pointer que vers l'objet String. Donc, si après la déclaration de tout à l'heure, si vous exécutez une autre phrase :
Chaîne chaîne = s ;
Nous avons déclaré une autre référence qui ne peut pointer que vers l'objet String, nommé string. Aucun deuxième objet String n'est toujours généré vers l'objet d'origine, c'est-à-dire qu'il pointe vers le même objet que s.
Question 2 : Quelle est la différence entre la méthode "==" et la méthode égale ?
L'opérateur == est spécifiquement utilisé pour comparer les valeurs des variables pour l'égalité. La chose la plus simple à comprendre est :
Copiez le code comme suit :
entier a=10 ;
entier b=10 ;
Alors a==b sera vrai.
Mais ce qui est difficile à comprendre, c'est :
Copiez le code comme suit :
Chaîne a=nouvelle Chaîne("foo");
Chaîne b=nouvelle Chaîne("foo");
Alors a==b renverra false.
Selon le post précédent, les variables d'objet sont en fait des références et leurs valeurs pointent vers l'adresse mémoire où se trouve l'objet, et non vers l'objet lui-même. a et b utilisent tous deux l'opérateur new, ce qui signifie que deux chaînes avec le contenu « foo » seront générées dans la mémoire. Puisqu'il y en a « deux », elles sont naturellement situées à des adresses mémoire différentes. Les valeurs de a et b sont en fait les valeurs de deux adresses mémoire différentes, donc en utilisant l'opérateur "==", le résultat sera faux. Il est vrai que les objets pointés par a et b ont le contenu « foo » et devraient être « égaux », mais l'opérateur == n'implique pas de comparaison du contenu des objets.
La comparaison du contenu des objets est exactement ce que fait la méthode equals.
Jetez un œil à la façon dont la méthode equals de l'objet Object est implémentée :
Copiez le code comme suit :
booléen égal(Objet o){
renvoie ceci ==o ;
}
Les objets Objet utilisent l'opérateur == par défaut. Ainsi, si votre classe auto-créée ne remplace pas la méthode equals, votre classe obtiendra le même résultat en utilisant equals et en utilisant ==. On peut également voir que la méthode égale de Object n'atteint pas l'objectif que la méthode égale devrait atteindre : comparer si le contenu de deux objets est égal. Étant donné que la réponse doit être déterminée par le créateur de la classe, Object laisse cette tâche au créateur de la classe.
Jetez un œil à une classe extrême :
Copiez le code comme suit :
Monstre de classe{
contenu de chaîne privée ;
...
booléen égal(Objet autre){ return true;}
}
J'ai remplacé la méthode égale. Cette implémentation fait que les comparaisons entre les instances Monster renvoient toujours true quel que soit leur contenu.
Ainsi, lorsque vous utilisez la méthode equals pour déterminer si le contenu d’un objet est égal, ne le tenez pas pour acquis. Parce que vous pensez peut-être qu'ils sont égaux, mais l'auteur de cette classe ne le pense pas, et la mise en œuvre de la méthode égale de la classe est contrôlée par lui. Si vous devez utiliser la méthode égale ou utiliser une collection basée sur un code de hachage (HashSet, HashMap, HashTable), veuillez consulter la documentation Java pour confirmer comment la logique égale de cette classe est implémentée.
Question 3 : String a-t-il changé ?
Non. Étant donné que String est conçu pour être une classe immuable, tous ses objets sont des objets immuables. Veuillez regarder le code suivant :
Copiez le code comme suit :
Chaîne s = "Bonjour" ;
s = s + "monde !";
La cible pointée par s a-t-elle changé ? Cette conclusion peut être facilement dérivée de celle du premier article de cette série. Voyons ce qui s'est passé. Dans ce code, s pointait à l'origine sur un objet String avec le contenu "Bonjour", puis nous avons effectué une opération + sur s. L'objet pointé par s a-t-il changé ? La réponse est non. A ce moment, s ne pointe plus vers l'objet d'origine, mais vers un autre objet String avec le contenu "Hello world!". L'objet d'origine existe toujours dans la mémoire, mais la variable de référence s ne pointe plus vers lui.
Grâce à l'explication ci-dessus, nous pouvons facilement tirer une autre conclusion. Si les chaînes sont fréquemment modifiées de diverses manières, ou modifiées de manière imprévisible, alors l'utilisation de String pour représenter une chaîne entraînera une surcharge de mémoire importante. Étant donné que l'objet String ne peut pas être modifié après sa création, un objet String est requis pour représenter chaque chaîne différente. À ce stade, vous devriez envisager d'utiliser la classe StringBuffer, qui permet la modification, plutôt que de générer un nouvel objet pour chaque chaîne différente. De plus, le changement de politique entre ces deux types est très simple.
En même temps, nous pouvons également savoir que si vous souhaitez utiliser une chaîne avec le même contenu, vous n’avez pas besoin de créer une nouvelle chaîne à chaque fois. Par exemple, si nous voulons initialiser une variable de référence String nommée s dans le constructeur et la définir sur la valeur initiale, nous devons procéder comme suit :
Copiez le code comme suit :
Démo de classe publique {
Chaînes privées ;
…
Démo publique {
s = « Valeur initiale » ;
}
…
}
Au lieu de s = new String("Initial Value");
Ce dernier appellera le constructeur à chaque fois pour générer un nouvel objet, qui a de faibles performances et une grande consommation de mémoire, et n'a aucun sens. Parce que l'objet String ne peut pas être modifié, un seul objet String peut être utilisé pour représenter une chaîne avec le même contenu. . En d'autres termes, si vous appelez le constructeur ci-dessus plusieurs fois pour créer plusieurs cibles, leurs attributs de type String pointeront tous vers la même cible.
La conclusion ci-dessus est également basée sur le fait que pour les constantes de chaîne, si le contenu est le même, Guangzhou Java Training estime qu'elles représentent le même objet String. Appeler le constructeur avec le mot-clé new créera toujours une nouvelle cible, que le contenu soit ou non le même.
Quant à la raison pour laquelle la classe String doit être décrite comme une classe immuable, elle est déterminée par son objectif. En fait, non seulement String, mais aussi de nombreuses classes de la bibliothèque de classes standard Java sont immuables. Lors du développement d'un système, nous devons parfois décrire des classes immuables pour transmettre un ensemble de valeurs liées, ce qui est également une manifestation d'une pensée orientée vers un objectif. Les classes immuables présentent certains avantages. Par exemple, comme leur objectif est en lecture seule, il n'y aura aucun problème d'accès simultané par plusieurs threads. Bien sûr, il existe également quelques inconvénients. Par exemple, chaque situation différente nécessite un objet pour la représenter, ce qui peut entraîner des problèmes fonctionnels. Par conséquent, la bibliothèque de classes standard Java fournit également une version variable, à savoir StringBuffer.