Java String引用传递问题
String类在主方法定义无法被方法修改但是如果实例化其他类并对对象修改String对象则可以修改,这其中原因是什么...
String类在主方法定义无法被方法修改
但是如果实例化其他类并对对象修改String对象则可以修改,这其中原因是什么 展开
但是如果实例化其他类并对对象修改String对象则可以修改,这其中原因是什么 展开
展开全部
了解数据在堆栈内存中的存储,这道问题就可以解了。
1.String对象传入方法后,str2是局部变量,方法结束之后,局部变量值会在缓冲区中。但是并没有修改成员变量str1的值,而输出的仍然是str1的值,"hello"。(局部变量和成员变量是不同的变量,即使名字相同)
2.至于第二个因为类的实例化,对象可以指向该类地址,可以访问该类的成员变量。对象指向成员变量temp,调用方法tell方法时,传入的是Ref2对象的地址。该地址可以找到Ref2的成员变量temp。然后把"xueyuan"赋给temp,由此temp的值已经改变,方法调用结束之后,输出的是Ref2类的已经改变值的成员变量
1.String对象传入方法后,str2是局部变量,方法结束之后,局部变量值会在缓冲区中。但是并没有修改成员变量str1的值,而输出的仍然是str1的值,"hello"。(局部变量和成员变量是不同的变量,即使名字相同)
2.至于第二个因为类的实例化,对象可以指向该类地址,可以访问该类的成员变量。对象指向成员变量temp,调用方法tell方法时,传入的是Ref2对象的地址。该地址可以找到Ref2的成员变量temp。然后把"xueyuan"赋给temp,由此temp的值已经改变,方法调用结束之后,输出的是Ref2类的已经改变值的成员变量
追问
第一种情况是因为形参在堆中开辟了新的空间而没有修改成功
第二种情况是改变了引用的指向导致了修改成功?
追答
引用的指向没有变吧,指向的是temp,把值赋给temp,指向还是temp
展开全部
java只有值传递,所有的方法参数都是变量的值的拷贝,对于基本变量,改变变量的拷贝没有任何意义,而对于引用变量,变量的值为引用对象的地址,变量的拷贝与原变量指向同一个对象,所以在方法中对于对象的修改(set方法)是全局性的,而“变量的拷贝 = 新对象”仅仅是开辟新的空间储存“新对象”,然后将“新对象”的地址赋给“变量的拷贝”,所以原变量无变化。
已赞过
已踩过<
评论
收起
你对这个回答的评价是?
展开全部
你是C/C++或是VB转过来的吗?在Java中过多考虑引用(指针)和值之间的关系是步入歧途,这正是Java的设计者极力避免你考虑的问题。
你需要明白的是:
1、Java中所有方法的参数的传递都是“值传递”;
2、Java中所有对象类型的变量的“值”,本质上说,包含了Java堆中的实际对象的地址,你可以大体认为Java的变量对应了C/C++中的指针(其实这里面有更复杂的机制)。事实上,Java并不像C/C++一样明确的区分“值语义”与“引用语义”,Java栈中也不会存放任何对象的实体(这点与C/C++不同,C/C++栈中可以存放对象实体),所有的Java对象都是在堆中。
概念上的区别在于,我这里提到的“变量”是指Java栈中的内容,对应你说的“引用”;我提到的“对象”是指Java堆中的实体,对应你说的“值”。而一般Java教材中提到的“值传递”,是指这些“变量”的内容的传递,不是Java堆中的对象实体的传递。
你用字符串来做实验,并推广为所有Java对象的做法,并不是特别合适。Java的String类型有特殊的处理:所有编译期认识的字符串,都会被放到常量池,于是下面的语句:
a = "s";
b = "s";
a和b并不像其它对象一样有创建的动作,都是直接指向常量池中的"s",所以你可以得到a==b。而下面的语句:
a = new String("s");
b = new String("s");
是分别在Java堆中创建了2个对象,此时a!=b。
本质上说,对于基本数据类型(整数、字符等),Java的符号==,用于判断二者的值是否相等;对于对象类型,Java的符号==,用于判断两个变量是否是“同一个对象”,equals()方法才是用于判断两个对象是否相等。
你希望实现的swap逻辑,在Java中通常认为是无法实现的。拿你这个例子来说,swapValue()中的tmpValue无论怎么更改,只是改变tmpValue自己的内容(即不断指向不同的对象),并不会改变value中的内容(始终指向同一个对象)。这也是为什么Java最初说自己永远是值传递。你只有改变tmpValue指向的对象的值(通过调用这个对象的方法或是更改它的属性),使用value访问时,才能看到这些改变。
为了弥补这个缺陷,C#才加入了ref关键字,允许传入变量的引用(如果参考C/C++,C#传递的实际是二级指针,它的内容是栈中的变量的地址)。
你需要明白的是:
1、Java中所有方法的参数的传递都是“值传递”;
2、Java中所有对象类型的变量的“值”,本质上说,包含了Java堆中的实际对象的地址,你可以大体认为Java的变量对应了C/C++中的指针(其实这里面有更复杂的机制)。事实上,Java并不像C/C++一样明确的区分“值语义”与“引用语义”,Java栈中也不会存放任何对象的实体(这点与C/C++不同,C/C++栈中可以存放对象实体),所有的Java对象都是在堆中。
概念上的区别在于,我这里提到的“变量”是指Java栈中的内容,对应你说的“引用”;我提到的“对象”是指Java堆中的实体,对应你说的“值”。而一般Java教材中提到的“值传递”,是指这些“变量”的内容的传递,不是Java堆中的对象实体的传递。
你用字符串来做实验,并推广为所有Java对象的做法,并不是特别合适。Java的String类型有特殊的处理:所有编译期认识的字符串,都会被放到常量池,于是下面的语句:
a = "s";
b = "s";
a和b并不像其它对象一样有创建的动作,都是直接指向常量池中的"s",所以你可以得到a==b。而下面的语句:
a = new String("s");
b = new String("s");
是分别在Java堆中创建了2个对象,此时a!=b。
本质上说,对于基本数据类型(整数、字符等),Java的符号==,用于判断二者的值是否相等;对于对象类型,Java的符号==,用于判断两个变量是否是“同一个对象”,equals()方法才是用于判断两个对象是否相等。
你希望实现的swap逻辑,在Java中通常认为是无法实现的。拿你这个例子来说,swapValue()中的tmpValue无论怎么更改,只是改变tmpValue自己的内容(即不断指向不同的对象),并不会改变value中的内容(始终指向同一个对象)。这也是为什么Java最初说自己永远是值传递。你只有改变tmpValue指向的对象的值(通过调用这个对象的方法或是更改它的属性),使用value访问时,才能看到这些改变。
为了弥补这个缺陷,C#才加入了ref关键字,允许传入变量的引用(如果参考C/C++,C#传递的实际是二级指针,它的内容是栈中的变量的地址)。
已赞过
已踩过<
评论
收起
你对这个回答的评价是?
展开全部
String对象无法被修改。你说的“修改”,修改的是引用的指向,也就是令本来指向String对象a的引用r,改而指向String对象b。String对象本身并没有改变,也不可变。
更多追问追答
追问
我理解第一种情况
但是第二种情况里形参为String开拓了新的内存空间并指向了它为什么会改变实参
追答
你传递的参数是一个指向Ref2类的引用r2,通过这个引用r2去修改这个Ref2对象中的一个属性的值,这个属性是一个指向String对象的引用。tell(r1)没有修改实参r1本身的指向,也无法修改。
本回答被提问者和网友采纳
已赞过
已踩过<
评论
收起
你对这个回答的评价是?
推荐律师服务:
若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询