web-dev-qa-db-fra.com

Paramètre de variable Java String - référence ou valeur?

Le segment de code Java suivant provient d’un examen pratique d’AP Computer Science.

String s1 = "ab";
String s2 = s1;
s1 = s1 + "c";
System.out.println(s1 + " " + s2);

La sortie de ce code est "abc ab" sur BlueJ. Cependant, l'un des choix de réponse possibles est "abc abc". La réponse peut être soit selon que Java définit la référence String comme des types primitifs (par valeur) ou comme des objets (par référence).

Pour illustrer cela davantage, examinons un exemple avec des types primitifs:

int s1 = 1;
int s2 = s1; // copies value, not reference
s1 = 42;

System.out.println(s1 + " " + s2); // prints "1 42"

Mais, disons que nous avions BankAccount objets qui détiennent des soldes.

BankAccount b1 = new BankAccount(500); // 500 is initial balance parameter
BankAccount b2 = b1; // reference to the same object
b1.setBalance(0);
System.out.println(b1.getBalance() + " " + s2.getBalance()); // prints "0 0"

Je ne suis pas sûr de ce qui est le cas avec Strings. Ils sont techniquement des objets, mais mon compilateur semble les traiter comme des types primitifs lors de la définition de variables. 

Si Java réussit les variables String de type primitif, la réponse est "abc ab". Toutefois, si Java traite les variables de chaîne comme des références à tout autre objet, la réponse serait "abc abc".

Selon vous, quelle est la bonne réponse?

17
ianonavy

Les chaînes Java sont immuables. Par conséquent, votre réaffectation fait en sorte que votre variable pointe sur une nouvelle instance de String au lieu de modifier la valeur de la chaîne.

String s1 = "ab";
String s2 = s1;
s1 = s1 + "c";
System.out.println(s1 + " " + s2);

sur la ligne 2, s1 == s2 ET s1.equals (s2). Après votre concaténation sur la ligne 3, s1 référence maintenant une instance différente avec la valeur immuable de "abc", donc ni s1 == s2 ni s1.equals (s2). 

27
digitaljoel

La différence entre votre compte bancaire et une chaîne est qu'une chaîne est immuable. 'SetValue ()' ou 'setContent ()' n'existe pas. L'exemple équivalent avec votre compte bancaire serait:

BankAccount b1 = new BankAccount(500); // 500 is initial balance parameter
BankAccount b2 = b1; // reference to the same object
b1 = new BankAccount(0);
System.out.println(b1.getBalance() + " " + s2.getBalance()); // prints "0 500"

Donc, si vous pensez de cette façon (pas exactement ce que fait le compilateur, mais fonctionnellement équivalent), le scénario de concaténation de chaîne est le suivant:

String s1 = "ab";
String s2 = s1;
s1 = new String("abc");
System.out.println(s1 + " " + s2); //prints "abc ab"
13
Affe

En effet, String est une classe et est assigné/passé par référence . Mais ce qui est déroutant, c’est l’affirmation suivante:

String s = "abc";

Ce qui suggère que String est une primitive (comme 'int x = 10;'); Mais ce n'est qu'un raccourci, la déclaration 'String s = "abc";' est en fait compilé comme 'String s = new String( "abc" );' Tout comme' Integer x = 10; 'est compilé comme' Integer x = new Integer( 10 ); '

Ce mécanisme s'appelle la «boxe».

Et plus déroutant: il y a une classe 'Integer' et une primitive 'int', Mais String n'a pas d'équivalent primitif (tout bien que char[] s'approche)

Sije de Haan

10
SijeDeHaan

Peu importe que String soit traité comme une primitive ou comme un objet!

Dans l'exemple String, la concaténation de deux chaînes produit une nouvelle instance String , qui est ensuite attribuée à s1. La variable s2 fait toujours référence à l'instance ancienne de String non modifiée (!).

En supposant que BankAccount dispose d'une méthode pour définir le solde, qui renvoie un nouveau BankAccount, votre exemple pourrait ressembler à ceci:

BankAccount b1 = new BankAccount(500); // 500 is initial balance parameter
BankAccount b2 = b1; // reference to the same object
b1 = b1.createNewAccountWithBalance(0); // create and reference a new object
System.out.println(b1.getBalance() + " " + b2.getBalance()); // prints "0 500"
10
Christian Semrau

En Java, les objets String sont affectés et transmis autour de par référence ; à cet égard, ils se comportent exactement comme n'importe quel autre objet.

Cependant, Strings sont immutable : il n'y a pas d'opération qui modifie la valeur d'une chaîne existante à la place, sans créer un nouvel objet. Par exemple, cela signifie que s1 = s1 + "c" crée un nouvel objet et remplace la référence stockée dans s1 par une référence à ce nouvel objet.

6
NPE

Stringest une classe, donc une String variable est une référence. Mais c'est un langage intrinsèque, en ce sens que Java a une manipulation et une syntaxe spéciales, raison pour laquelle vous pouvez faire des choses comme votre exemple.

Voir par exemple http://download.Oracle.com/javase/tutorial/Java/nutsandbolts/datatypes.html .

4

Java.lang.String est un objet, pas une primitive.

Ce que le code a fait dans le premier exemple est le suivant:

  1. Définir s1 comme "ab"
  2. Définissez s2 égal au même objet sous-jacent que s1
  3. Définissez s1 égal à une nouvelle chaîne qui est la combinaison de l'ancienne valeur de s1 et de "c"

Mais pour répondre à votre question sur la référence ou la valeur, c'est par référence.

3
Mike Thomsen

L'assertion

si Java traite les variables de chaîne comme des références à tout autre objet, la réponse serait "abc abc"

est incorrect. Java traite les variables de chaîne comme des références à tout autre objet. Strings sont des objets mais la réponse est "abc ab" néanmoins.

Le problème n’est pas ce que l’opérateur d’affectation fait. L'opérateur d'affectation attribue une référence à un objet String dans chaque cas de votre exemple.

Le problème est ce que fait l'opérateur de concaténation ('+'). Il crée un nouvel objet String. Comme d'autres l'ont déjà dit, cela est nécessaire car un objet String est immuable, mais il s'agit d'un problème de comportement de l'opérateur et pas simplement parce que String est immuable. L'opérateur de concaténation peut renvoyer un nouvel objet même si un objet String est modifiable.

En revanche, dans votre deuxième exemple, b1.setBalance (0) ne crée pas de nouvel objet, il modifie l'objet existant.

1
Ian
int s1 = 1;
int s2 = s1; // copies value, not reference
s1 = 42;

System.out.println(s1 + " " + s2); // prints "1 42"

N'imprime pas "1 42" mais "42 1". Tenez compte de chaque ligne discrète. Tout d'abord, s1 attribue 1, puis s2, s1, qui est égal à 1 jusqu'à présent (supposons que Java n'ait pas encore vu la troisième ligne.) Puis Java voit la troisième ligne. et change immédiatement s1 en 42. Après cela, on a demandé à Java d’imprimer ce qu’il savait jusqu’à maintenant, c’est-à-dire que s1 est 42 et s2 est 1 (l’ancien s1).

En ce qui concerne la chaîne, la même chose se produit.

String s1 = "ab";
String s2 = s1;
s1 = s1 + "c";
System.out.println(s1 + " " + s2);// prints "abc ab".

Fort String il ne change pas nécessairement s1 mais plutôt s1 fait maintenant référence à un nouvel objet String dans la mémoire de tas, mais l'ancien objet "ab" est toujours là, avec une nouvelle référence de s2!

0
Rafsan Mobasher