Maison > Questions et réponses > le corps du texte
1、问题描述
java方法传String类型的参数时,为啥方法对值的修改没有在方法之外生效?假设是其他类型的对象,那么方法对对象的数据的修改是会在方法之外生效的啊,可是String类型也是对象类型啊,为啥就没有在方法之外生效呢?
2、代码示例
//示例1:对象类型
public class PassReferByValue
{
String a = "123";
public static void test(PassReferByValue test)
{
test.a = "abc";
}
public static void main(String[] args)
{
PassReferByValue test = new PassReferByValue();
System.out.println("对象的数据的初始值是:" + test.a); //123
test(test);
System.out.println("通过调用test方法修改对象的数据的值之后:" + test.a); //abc
}
}
总结:因为是对象类型,所以方法每次修改对象的数据的值之后,都在方法之外生效了,也就是说,在方法之外和在方法之内访问到的对象的数据的值是一致的。
//示例2:String类型
public class Test
{
public static void test(String str)
{
str = "word";
}
public static void main(String[] args)
{
String string = "hello";
System.out.println("对象的数据的初始值是:" + string); //hello
test(string);
System.out.println("通过调用test方法修改对象的值之后还是以前的值:" + string); //hello
}
}
总结:如果方法的参数是String类型,虽然方法修改了它的值,但是并没有在方法之外生效,也就是说,在方法之外和在方法之内的访问到的值不一样!!!这是为什么???
3、网上的解释
String等immutable类型因为没有提供自身修改的函数,每次操作都是新生成一个对象,所以要特殊对待。
http://blog.csdn.net/fbysss/article/details/3082949
这样的解释太肤浅了,完全是基于文字的描述,有没有基于代码层面的解释,或者其他的更深层次的解释呢?
阿神2017-04-18 09:15:32
Selon votre compréhension
L'exemple 1 est bien vrai 对象的数据的修改
, mais l'exemple 2 est vrai 参数本身的修改
Qu'il s'agisse d'un passage par valeur ou d'un passage par référence, c'est essentiellement la même chose que 值传递
Lorsque la méthode est appelée, la valeur du paramètre est calculée et une copie est donnée au paramètre correspondant
Uniquement pour les types d'objet, la valeur de référence (ou comprise comme pointeur, adresse) de l'objet est transmise. Bien que le paramètre obtienne une référence copiée, il pointe vers le même objet que la référence d'origine, donc selon cette référence, vous pouvez exploiter les données de l'objet d'origine
Dans votre deuxième exemple, lors de l'appel de la méthode, calculez la valeur du paramètre string
(qui peut être compris comme l'adresse de l'objet chaîne hello
en mémoire) et copiez-la dans le paramètre str
, bien que le paramètre str
ait obtenu la référence à l'objet chaîne hello
d'origine (c'est-à-dire que la valeur de str
est égale à la valeur de string
, c'est-à-dire l'adresse de hello
), mais immédiatement a donné ce paramètre Réaffecter. À l'heure actuelle, le paramètre str
n'a rien à voir avec la chaîne hello
str
ne pointe plus vers hello
mais pointe vers world
. et hello
Il n'y a aucun changement dans l'adresse en mémoire, et la variable hello
en dehors de la méthode pointe toujours vers l'objet chaîne string
sans aucun changement hello
天蓬老师2017-04-18 09:15:32
Pour résumer en trois phrases :
1 对象
est 传引用
2 原始类型
est 传值
3. Fonction de modification, chaque opération génère un nouvel objet, il doit donc être traité spécialement. Cela peut être considéré comme un passage par valeur. String,Integer, Double
Integer est identique à String. La variable de classe qui contient la valeur est une propriété Final et ne peut pas être modifiée. Elle peut uniquement être réaffectée/générer un nouvel objet. Lorsqu'un entier est transmis à la méthode en tant que paramètre de méthode, son affectation fera pointer la référence de l'entier d'origine vers l'adresse de la pile dans la méthode, perdant ainsi le pointeur vers l'adresse de la variable de classe d'origine. Toute opération effectuée sur l’objet Integer attribué n’affectera pas l’objet d’origine.
Description du lien
PHPz2017-04-18 09:15:32
test1.a = "567"
, ce que vous modifiez ici, c'est l'attribut test1
de l'objet référencé par
str = "word"
Ce que vous modifiez ici, c'est l'objet pointé par la variable de référence str
.
Pour faire simple, il y en a deux, Xiao Ming et Xiao Hong Si vous remplacez la main de Xiao Ming par une main de robot, la main de Xiao Ming sera vraiment changée, mais si vous changez le nom de Xiao Hong en Xiao Ming... Xiao Hong lui-même n'est toujours pas le même.
Plus profondément, Xiao Ming et Xiao Hong vont participer à un événement. L'événement ne nécessite pas que vous connaissiez votre vrai nom, ils se voient donc attribuer les noms de code A et B. À ce moment-là, A a été blessé pendant l'activité et la poignée a été remplacée par une main mécanique. En conséquence, après l'activité, la main de Xiao Ming a effectivement été remplacée par une main mécanique. Mais B vient d'échanger le badge contre C. Après sa sortie, Xiao Hong est toujours Xiao Hong et n'est pas devenu la personne correspondant à C.
Ici, l'activité est la méthode, et le code attribué est le paramètre formel. L'attribution directe de valeurs aux paramètres formels n'affectera pas les paramètres réels, mais l'attribution de valeurs aux propriétés de l'objet référencé par. les paramètres formels ont en fait affecté les propriétés de l'objet.
Je vais ajouter un morceau de code avec des commentaires pour voir si cela peut vous aider à comprendre. Si vous voulez comprendre que le véritable processus d’appel de méthode implique également des connaissances telles que la pile, ce n’est pas si compliqué. Ce code n'a aucune sortie. Vous pouvez essayer d'ajouter une sortie après l'avoir compris pour vérifier si votre compréhension est correcte.
public class PassReferByValue
{
String a = "123";
public static void test(PassReferByValue test)
{
test.a = "abc";
}
public static void test2(PassReferByValue test) {
test = new PassReferByValue();
test.a = "cde";
}
public static void test3(String s) {
s = "world";
}
public static void main(String[] args)
{
PassReferByValue obj = new PassReferByValue();
// -----------------------------------------------
// test(obj);
// 如果把这个调用过程展开,代码就像这样(为了便于识别,我改了下变量名
// 说明一下:下面用 { } 代码段主要是为了限定里面的变量作用域
// 进入 test(obj);
{
PassReferByValue test = obj;
test.a = "abc";
}
// 没有返回类型,所以这里方法直接结束,出来
// ------------------------------------------------
// 现在来展开 test2(obj);
{
PassReferByValue test = obj;
test = new PassReferByValue(); // test 是一个新对象,不是 obj 了
test.a = "cde"; // 改变的是新对象,对 obj 没有影响
}
// 所以方法调用结束之后 obj 还是没变,还是 obj.a.equals("abc");
// -------------------------------------------------
// 现在来看 string 的情况
String hello = "hello";
// 这里开始展开 test3(hello);
{
String s = hello;
s = "world"; // 这里修改了 s 引用的对象,但没有修改 hello 引用的对象
// 所以 hello.equals("hello"), s.equals("world");
}
}
}
PHPz2017-04-18 09:15:32
À l'exception de String, les autres objets en Java sont passés par référence.
高洛峰2017-04-18 09:15:32
//示例2:String类型
public class Test
{
public static void test(String str)
{
//str这个变量作用域在test这个函数里,原本指向"hello",现在指向"word"
str = "word";
}
public static void main(String[] args)
{
String string = "hello";
System.out.println("对象的数据的初始值是:" + string); //hello
test(string);
System.out.println("通过调用test方法修改对象的值之后还是以前的值:" + string); //hello
}
}
J'ai évoqué des points de connaissances pertinents au début d'une de mes chroniques. Voyant que vous êtes un peu confus, j'aimerais vous le recommander.
阿神2017-04-18 09:15:32
String est un type immuable, ce qui signifie que sa valeur est immuable. Par exemple, String a = "abc"
, dans la mémoire, la référence a pointe vers le bloc mémoire "abc". Lors de l'utilisation de a = "bcd"
, la valeur du bloc mémoire où se trouve "abc" n'est pas changée en "bcd", mais une autre chaîne est générée. "bcd", puis pointez a vers "bcd", donc la référence en dehors de la méthode pointe toujours vers la mémoire de "abc".
Le type de variable modifiera directement la valeur de la mémoire où se trouve "abc" De cette façon, la référence en dehors de la méthode pointe toujours vers l'adresse mémoire d'origine, donc la valeur modifiée est accessible en dehors de la méthode.
阿神2017-04-18 09:15:32
La chaîne contenue dans l'objet String ne peut pas être modifiée. Lorsqu'une variable de type String est réaffectée, sa référence changera également et deviendra un nouvel objet.