Passer une chaîne par référence en Java?

Je suis habitué à faire ce qui suit en C :

 void main() { Ssortingng zText = ""; fillSsortingng(zText); printf(zText); } void fillSsortingng(Ssortingng zText) { zText += "foo"; } 

Et la sortie est la suivante:

 foo 

Cependant, en Java, cela ne semble pas fonctionner. Je suppose que l’object Ssortingng est copié au lieu de passé par référencé . Je pensais que les cordes étaient des objects qui sont toujours passés par référence.

Qu’est-ce qui se passe ici?

Vous avez trois options:

  1. Utilisez un SsortingngBuilder:

     SsortingngBuilder zText = new SsortingngBuilder (); void fillSsortingng(SsortingngBuilder zText) { zText.append ("foo"); } 
  2. Créez une classe de conteneur et transmettez une instance du conteneur à votre méthode:

     public class Container { public Ssortingng data; } void fillSsortingng(Container c) { c.data += "foo"; } 
  3. Créez un tableau:

     new Ssortingng[] zText = new Ssortingng[1]; zText[0] = ""; void fillSsortingng(Ssortingng[] zText) { zText[0] += "foo"; } 

Du sharepoint vue des performances, SsortingngBuilder est généralement la meilleure option.

En Java rien n’est passé par référence . Tout est passé par valeur . Les références aux objects sont transmises par valeur. De plus, les chaînes sont immuables . Donc, lorsque vous ajoutez à la chaîne passée, vous obtenez juste une nouvelle chaîne. Vous pouvez utiliser une valeur de retour ou passer un SsortingngBuffer à la place.

Ce qui se passe, c’est que la référence est passée par valeur, c’est-à-dire qu’une copie de la référence est transmise. Rien dans java n’est passé par référence, et comme une chaîne est immuable, cette affectation crée un nouvel object chaîne auquel la copie de la référence pointe maintenant. La référence d’origine pointe toujours sur la chaîne vide.

Ce serait la même chose pour n’importe quel object, c.-à-d. La définir sur une nouvelle valeur dans une méthode. L’exemple ci-dessous rend plus évident ce qui se passe, mais concaténer une chaîne est vraiment la même chose.

 void foo( object o ) { o = new Object( ); // original reference still points to old value on the heap } 

java.lang.Ssortingng est immuable.

Je déteste coller des URL, mais https://docs.oracle.com/javase/10/docs/api/java/lang/Ssortingng.html est essentiel pour que vous lisiez et compreniez si vous êtes en java-land.

les objects sont passés par référence, les primitives sont transmises par valeur.

Ssortingng n’est pas une primitive, c’est un object et c’est un cas particulier d’object.

C’est pour des raisons d’économie de mémoire. Dans JVM, il y a un pool de chaînes. Pour chaque chaîne créée, JVM essaiera de voir si la même chaîne existe dans le pool de chaînes et indique si une chaîne existe déjà.

 public class TestSsortingng { private static Ssortingng a = "hello world"; private static Ssortingng b = "hello world"; private static Ssortingng c = "hello " + "world"; private static Ssortingng d = new Ssortingng("hello world"); private static Object o1 = new Object(); private static Object o2 = new Object(); public static void main(Ssortingng[] args) { System.out.println("a==b:"+(a == b)); System.out.println("a==c:"+(a == c)); System.out.println("a==d:"+(a == d)); System.out.println("a.equals(d):"+(a.equals(d))); System.out.println("o1==o2:"+(o1 == o2)); passSsortingng(a); passSsortingng(d); } public static void passSsortingng(Ssortingng s) { System.out.println("passSsortingng:"+(a == s)); } } 

/ * SORTIE * /

 a==b:true a==c:true a==d:false a.equals(d):true o1==o2:false passSsortingng:true passSsortingng:false 

le == vérifie l’adresse mémoire (référence), et le .equals vérifie le contenu (valeur)

Ssortingng est un object immuable en Java. Vous pouvez utiliser la classe SsortingngBuilder pour effectuer le travail que vous essayez d’accomplir, comme suit:

 public static void main(Ssortingng[] args) { SsortingngBuilder sb = new SsortingngBuilder("hello, world!"); System.out.println(sb); foo(sb); System.out.println(sb); } public static void foo(SsortingngBuilder str) { str.delete(0, str.length()); str.append("Ssortingng has been modified"); } 

Une autre option consiste à créer une classe avec une chaîne sous la forme d’une variable de scope (fortement déconseillée) comme suit:

 class MySsortingng { public Ssortingng value; } public static void main(Ssortingng[] args) { MySsortingng ms = new MySsortingng(); ms.value = "Hello, World!"; } public static void foo(MySsortingng str) { str.value = "Ssortingng has been modified"; } 

Les chaînes sont passées par référence (eh bien, à proprement parler, comme le note Ed Swangren, une référence à la chaîne est passée par valeur ) mais elles sont immuables.

 zText += foo; 

est équivalent à:

 zText = new Ssortingng(zText + "foo"); 

En d’autres zText , il modifie la variable (locale) zText sorte qu’elle pointe maintenant vers un nouvel emplacement mémoire, dans lequel se trouve une Ssortingng avec le contenu d’origine de zText , avec "foo" ajouté. L’object d’origine n’est pas modifié et la variable locale de la méthode main() zText pointe toujours vers la chaîne d’origine (vide).

 class SsortingngFiller { static void fillSsortingng(Ssortingng zText) { zText += "foo"; System.out.println("Local value: " + zText); } public static void main(Ssortingng[] args) { Ssortingng zText = ""; System.out.println("Original value: " + zText); fillSsortingng(zText); System.out.println("Final value: " + zText); } } 

estampes:

 Original value: Local value: foo Final value: 

Si vous souhaitez modifier la chaîne, vous pouvez, comme indiqué, utiliser SsortingngBuilder ou un conteneur (un tableau ou une classe de conteneur personnalisée) qui vous donne un niveau supplémentaire d’indirection du pointeur. Sinon, retournez simplement la nouvelle valeur et assignez-la:

 class SsortingngFiller2 { static Ssortingng fillSsortingng(Ssortingng zText) { zText += "foo"; System.out.println("Local value: " + zText); return zText; } public static void main(Ssortingng[] args) { Ssortingng zText = ""; System.out.println("Original value: " + zText); zText = fillSsortingng(zText); System.out.println("Final value: " + zText); } } 

estampes:

 Original value: Local value: foo Final value: foo 

C’est probablement la solution la plus proche de Java dans le cas général – voir l’élément Java effectif «Favoriser l’immutabilité».

Comme indiqué SsortingngBuilder , SsortingngBuilder vous donnera souvent de meilleures performances – si vous avez beaucoup à faire, en particulier dans une boucle, utilisez SsortingngBuilder .

Mais essayez de faire circuler des Ssortingngs immuables plutôt que des SsortingngBuilders mutables si vous le pouvez – votre code sera plus facile à lire et plus facile à maintenir. Pensez à rendre vos parameters final et à configurer votre IDE pour qu’il vous avertisse lorsque vous réaffectez un paramètre de méthode à une nouvelle valeur.

Ssortingng est une classe spéciale en Java. C’est le Thread Save qui signifie “Une fois qu’une instance Ssortingng est créée, le contenu de l’instance Ssortingng ne changera jamais”.

Voici ce qui se passe pour

  zText += "foo"; 

Tout d’abord, le compilateur Java récupérera la valeur de l’instance zText Ssortingng, puis créera une nouvelle instance Ssortingng dont la valeur est zText et ajoute “foo”. Donc, vous savez pourquoi l’instance pointée par zText n’a pas changé. C’est totalement une nouvelle instance. En fait, même Ssortingng “foo” est une nouvelle instance de Ssortingng. Donc, pour cette instruction, Java va créer deux instances de Ssortingng, l’une est “foo”, une autre est la valeur de zText append “foo”. La règle est simple: la valeur de l’instance Ssortingng ne sera jamais modifiée.

Pour la méthode fillSsortingng, vous pouvez utiliser un SsortingngBuffer en tant que paramètre, ou vous pouvez le modifier comme suit:

 Ssortingng fillSsortingng(Ssortingng zText) { return zText += "foo"; } 

La réponse est simple. En java, les chaînes sont immuables. D’où son utilisation du modificateur ‘final’ (ou ‘const’ en C / C ++). Donc, une fois assigné, vous ne pouvez pas le changer comme vous l’avez fait.

Vous pouvez changer la valeur à laquelle une chaîne pointe, mais vous ne pouvez PAS modifier la valeur réelle sur laquelle cette chaîne pointe actuellement.

C’est à dire. Ssortingng s1 = "hey" . Vous pouvez créer s1 = "woah" , et c’est tout à fait correct, mais vous ne pouvez pas réellement changer la valeur sous-jacente de la chaîne (dans ce cas: “hey”) pour qu’elle soit affectée avec plusEquals, etc. . s1 += " whatup != "hey whatup" ).

Pour ce faire, utilisez les classes SsortingngBuilder ou SsortingngBuffer ou d’autres conteneurs mutables, puis appelez simplement .toSsortingng () pour reconvertir l’object en chaîne.

note: les chaînes sont souvent utilisées comme clés de hachage, ce qui explique en partie pourquoi elles sont immuables.

Les chaînes sont immuables en Java.

Cela fonctionne en utilisant SsortingngBuffer

 public class test { public static void main(Ssortingng[] args) { SsortingngBuffer zText = new SsortingngBuffer(""); fillSsortingng(zText); System.out.println(zText.toSsortingng()); } static void fillSsortingng(SsortingngBuffer zText) { zText .append("foo"); } } 

Encore mieux utiliser SsortingngBuilder

 public class test { public static void main(Ssortingng[] args) { SsortingngBuilder zText = new SsortingngBuilder(""); fillSsortingng(zText); System.out.println(zText.toSsortingng()); } static void fillSsortingng(SsortingngBuilder zText) { zText .append("foo"); } } 

La chaîne est immuable dans Java. vous ne pouvez pas modifier / modifier un littéral / object de chaîne existant.

Ssortingng s = “Bonjour”; s = s + “salut”;

Ici, la référence précédente s est remplacée par la nouvelle référence pointant vers la valeur “HelloHi”.

Cependant, pour apporter de la mutabilité, nous avons SsortingngBuilder et SsortingngBuffer.

SsortingngBuilder s = nouveau SsortingngBuilder (); s.append (“Hi”);

ceci ajoute la nouvelle valeur “Hi” aux mêmes références. //

Aaron Digulla a la meilleure réponse à ce jour. Une variante de sa deuxième option consiste à utiliser le wrapper ou la classe de conteneur MutableObject de la bibliothèque commons lang version 3+:

 void fillSsortingng(MutableObject c) { c.setValue(c.getValue() + "foo"); } 

vous enregistrez la déclaration de la classe de conteneur. L’inconvénient est une dépendance à la lib commons lang. Mais la lib a beaucoup de fonctions utiles et presque tous les projets plus importants sur lesquels je travaillais l’utilisaient.

Pour transmettre un object (y compris Ssortingng) par référence dans java, vous pouvez le transmettre en tant que membre d’un adaptateur environnant. Une solution avec un générique est ici:

 import java.io.Serializable; public class ByRef implements Serializable { private static final long serialVersionUID = 6310102145974374589L; T v; public ByRef(T v) { this.v = v; } public ByRef() { v = null; } public void set(T nv) { v = nv; } public T get() { return v; } // ------------------------------------------------------------------ static void fillSsortingng(ByRef zText) { zText.set(zText.get() + "foo"); } public static void main(Ssortingng args[]) { final ByRef zText = new ByRef(new Ssortingng("")); fillSsortingng(zText); System.out.println(zText.get()); } }