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
According to your understanding
Example 1 is indeed correct对象的数据的修改
,但是示例二却是对参数本身的修改
Whether it is passing by value or passing by reference, the essence is 值传递
. When the method is called, the value of the parameter is calculated and a copy is given to the corresponding parameter
Only for object types, the reference (or understood as pointer, address) value of the object is passed. Although the parameter gets a copied reference, it points to the same object as the original reference, so it can be operated based on this reference. Data of the original object
In your second example, when calling the method, the calculated parameter string
的值(可以理解为hello
这个字符串对象在内存中的地址),拷贝给参数str
,参数str
虽然拿到了原来hello
字符串对象的引用(即str
的值等于string
的值,也即hello
的地址),但是立马给这个参数重新赋值,这个时候str
参数已经跟hello
字符串没有任何关系了,str
不再指向hello
,改指向world
了,但是这个过程中hello
自身以及hello
在内存中的地址没有任何变化,方法外部的string
变量也一直指向hello
the string object has no changes
天蓬老师2017-04-18 09:15:32
To summarize in three sentences:
1. Object
is pass by reference
对象
就是传引用
2.原始类型
就是传值
3.String,Integer, Double
2. Primitive type
is pass by value
3. String, Integer, Double
and other immutable types do not provide functions for modifying themselves. Each operation generates a new object, so they must be treated specially. It can be considered as passing by value.
Integer is the same as String. The class variable that holds the value is a Final property and cannot be modified. It can only be reassigned/generate a new object. When an Integer is passed into the method as a method parameter, the assignment to it will cause the reference of the original Integer to be pointed to the stack address within the method, losing the pointer to the original class variable address. Any operation performed on the assigned Integer object will not affect the original object.
PHPz2017-04-18 09:15:32
test1.a = "567"
,这里你改的是 test1
Properties of the referenced object
str = "word"
你这里改的是引用变量 str
The object pointed to.
To put it simply, there are two, Xiao Ming and Xiao Hong. If you replace Xiao Ming’s hand with a robot hand, Xiao Ming’s hand will really be changed, but if you change Xiao Hong’s name to Xiao Ming... Xiao Hong herself will not change. .
Deeper, Xiao Ming and Xiao Hong went to participate in an event. The event did not need to know your real name, so they were assigned code names A and B. At this time, A was injured during the activity and the handle was replaced with a mechanical one. As a result, after the activity, Xiao Ming's hand had indeed been replaced by a mechanical one. But B just exchanged the name tag for C. After coming out, Xiao Hong is still Xiao Hong and has not become the person corresponding to C.
Here, the activity is the method, and the assigned code is the formal parameter. Direct assignment of values to the formal parameters will not affect the actual parameters, but assigning values to the properties of the object referenced by the formal parameters has actually affected the properties of the object.
I’ll add a piece of code with comments to see if it can help you understand. If you want to understand that the real process of method calling also involves knowledge such as the stack, it is not so complicated. This code has no output. You can try to add some output after understanding it to verify whether your understanding is correct.
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");
}
}
}
高洛峰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
}
}
I mentioned some relevant knowledge points at the beginning of one of my columns. Seeing that you are a little confused, I would like to recommend it to you.
阿神2017-04-18 09:15:32
String is an immutable type, which means its value is immutable. For example, when String a = "abc"
,在内存中a这个引用指向"abc"这块内存,当使用a = "bcd"
, the value of the memory block where "abc" is located is not changed to "bcd", but a separate string "bcd" is generated, and then a points to "bcd", so the reference outside the method still points to "abc" this memory.
The variable type will directly modify the value of the memory where "abc" is located. In this way, the reference outside the method still points to the original memory address, so the modified value can be accessed outside the method.
阿神2017-04-18 09:15:32
The string contained in the String object cannot be modified. When a String type variable is reassigned, its reference will also change and become a new object.