2009-01-31 9 views
2

J'ai un problème avec la compréhension de l'action de Java dans l'exemple suivant « passage par valeur »:Java, passer par valeur, les variables de référence

public class Numbers { 

    static int[] s_ccc = {7}; 
    static int[] t_ccc = {7}; 

    public static void calculate(int[] b, int[] c) { 

     System.out.println("s_ccc[0] = " + s_ccc[0]); // 7 
     System.out.println("t_ccc[0] = " + t_ccc[0]); // 7 

     b[0] = b[0] + 9; 
     System.out.println("\nb[0] = " + b[0]); // 16 

     c = b; 
     System.out.println("c[0] = " + c[0] + "\n"); // 16 
    } 

    public static void main(String[] args) { 

     calculate(s_ccc, t_ccc); 

     System.out.println("s_ccc[0] = " + s_ccc[0]); // 16 
     System.out.println("t_ccc[0] = " + t_ccc[0]); // 7 
    } 
} 

Je le sais parce s_ccc est une référence variable, quand je le donne à la méthode calculate() et que je fais quelques changements à ses éléments dans la méthode, les changements restent même après que j'ai quitté la méthode. Je pense que la même chose devrait être avec t_ccc. C'est à nouveau une variable de référence, je la donne à la méthode calculate(), et dans la méthode je change la référence à t_ccc pour qu'elle soit celle de s_ccc. Maintenant t_ccc devrait être une variable de référence pointant vers un tableau, qui a un élément de type entier égal à 16. Mais quand la méthode calculate() est à gauche, il semble que t_ccc pointe son ancien objet. Pourquoi cela arrive-t-il? Le changement ne devrait-il pas rester pour lui aussi? C'est une variable de référence après tout.

Cordialement

+0

Voulez-vous dire calculer (s_ccc, t_ccc) au lieu de calculer (s_ccc, s_ccc)? –

+0

Oui, exactement! Je veux dire calculer (s_ccc, t_ccc). Je suis désolé. – user42155

+0

@gemm: Pourriez-vous modifier votre message s'il vous plaît? –

Répondre

7

Il y a une discussion approfondie de la façon dont Java transmet des variables à une question précédente "Is Java pass by reference?". Java passe réellement les références d'objet par la valeur.

Dans votre code, les références des tableaux (qui sont des objets) sont passées dans calculate(). Ces références sont transmises par valeur, ce qui signifie que toutes les modifications apportées aux valeurs b et c sont visibles uniquement dans la méthode (il s'agit en réalité d'une copie de s_ccc et t_ccc). C'est pourquoi t_ccc dans main() n'a jamais été affecté.

Pour renforcer ce concept, certains programmeurs déclarent les paramètres de la méthode comme final variables

public static void calculate(final int[] b, final int[] c) 

Maintenant, le compilateur ne vous permet même de modifier les valeurs de b ou c. Bien sûr, l'inconvénient de ceci est que vous ne pouvez plus les manipuler commodément dans votre méthode.

6

La méthode reçoit des variables par valeur. Ces valeurs ne peuvent pas être changées (aussi loin que l'appelant de la méthode voit), mais les valeurs contenues dedans peuvent (si c'est un objet, ou comme dans ce cas, un tableau). Ainsi, lorsque vous modifiez la valeur b [0] à l'intérieur de la matrice, le changement peut être vu en dehors de la méthode. Cependant, la ligne

c = b; 

va changer la valeur de c dans la méthode, mais ce changement ne sera pas vu en dehors de la méthode, puisque la valeur de c a été adoptée par la valeur.

5

La ligne calculate(s_ccc, s_ccc); indique que vous ne faites rien à t_ccc. Cependant, si cette ligne a lu calculate(s_ccc, t_ccc); alors l'effet reste le même.

Cela est dû au fait que vous attribuer une nouvelle valeur à c ici: c = b;
Lors de l'attribution d'une nouvelle valeur à un argument de référence de la référence est perdue.
Ceci est la différence entre la modification d'une variable par référence et l'attribution d'une nouvelle valeur.

1

En entrée à calculate(), b points à s_ccc et c points à t_ccc.Modifier b[0] va donc changer s_ccc, comme vous l'avez vu.

Cependant, l'affectation

c = b; 

seuls les points c au même objet b montre du doigt, à savoir s_ccc. Il ne copie pas le contenu de ce que b points à ce que c points à. Par conséquent, t_ccc est inchangé. Si vous avez ajouté la ligne suivante à la fin de calculate():

c[0] = c[0] + 5; 

s_ccc[0] serait 21.

7

Voici une façon simple de le comprendre.

Java transmet toujours des copies d'arguments. Si l'argument est un type primitif (par exemple un entier), la méthode appelée obtient une copie de la valeur primitive. Si l'argument est un type de référence, la méthode appelée obtient une copie de la référence (et non une copie de la référence).

Lorsque votre méthode main commence, chacun s_ccc et t_ccc fait référence à un tableau distinct. Telle est la situation, où entre parenthèses indiquent les variables et les crochets indiquent les structures de tableaux réels:

(s_ccc) ---> [7] 
(t_ccc) ---> [7] 

En supposant que vous vouliez dire calculate(s_ccc, t_ccc), puis au début de la méthode calculate:

(s_ccc) ---> [7] <---(b) 
(t_ccc) ---> [7] <---(c) 

sections locales b et c sont copies respectivement des globaux s_ccc et t_ccc.

Toujours dans calculcate, après b[0] = b[0] + 9 a terminé:

(s_ccc) ---> [16] <---(b) 
(t_ccc) ---> [7] <---(c) 

La position de zéro (uniquement) dans le tableau désigné par b a été modifié.

L'affectation au sein c = bcalculate produit cette situation:

(s_ccc) ---> [16] <---(b) 
       ^------(c) 
(t_ccc) ---> [7] 

La variable de référence locale c, contient maintenant la même référence que b. Cela n'a aucun effet sur la variable de référence globale t_ccc, qui fait toujours référence au même tableau que précédemment.

Lorsque calculate se termine, ses variables locales (du côté droit des diagrammes) disparaissent. Les variables globales (sur le côté gauche) n'ont pas été utilisées dans calculate, elles ne sont donc pas affectées. La situation finale est:

(s_ccc) ---> [16] 
(t_ccc) ---> [7] 

Ni c_ccc ni t_ccc ont été changés; chacun se réfère toujours au même tableau qu'avant calculate.L'appel calculate a modifié le contenu du tableau référencé par s_ccc, en utilisant une référence copiée dans ce tableau (dans b).

Variable locale c a commencé comme une copie de t_ccc et a été manipulé au sein calculate, mais qui a changé ni t_ccc lui-même ni ses données référencées.

Questions connexes