黑马程序员技术交流社区
标题:
Java传的到底是值还是引用
[打印本页]
作者:
不抛弃不放弃
时间:
2013-11-10 12:44
标题:
Java传的到底是值还是引用
找高手! 我要找高手!。为什么经过方法处理后,得到的结果不一样?代码如下:
public class Test{
public void addInt(int i){
i+=1;
}
public void addStr(String str) { str+="111" };
public void addList(List<String> strList){ strList.add("List111");}
public static void main(String []args){
int i=0;
String str="s";
List<String> strList= new ArrayList<String>();
Test t= new Test();
t.addInt(i);
t.addStr(str);
t.addList(strList);
System.out.println(i); //输出0,为什么不是1
System.out.println(str); // 输出s;为什么不是s111
System.out.println(strList.get(0)); //输出List111,为什么就是这个可以
}
}
为什么int类型和String类型的变量经过方法处理后值没变,而List类型的变量值却变了?
作者:
零下五度的水
时间:
2013-11-10 13:10
这个跟Java语言无关,每种语言都是这么定义的,
对于方法的参数
栈中值的改变无效,堆中值的改变保留
int 是基本类型,值直接存放在栈中
String 是final类,值改变会新建一个对象,相当于重新在栈中赋值(指向的堆地址改变了)
List 是类,只会改变堆中的信息,所以改动被保留
作者:
文涛
时间:
2013-11-10 13:14
java准确的说是传值,不是传引用。
java的传值分两种情况,一是常规数据类型如int,double,二是对象,就如你的test。对于int等这种普通数据类型当然就跟c一样,只是简单的传值,所以你调用 t.addInt(i);,只是变量i的值被传递进方法,只是传递了一个副本,所以addIn方法里面的i和外部的i不是一个变量,是两个独立的变量,所以操作与外部定于的i无关。所以输出还是0.
对于 t.addStr(str);这个方法则稍稍不同,str是一个字符串对象,所以传值不是简单的传递一个副本那么简单,而是传递了指向字符串"s"的引用(指针)给函数addStr(String str),所以,在addStr中的str是一个新的指针,指向了"s",而字符串是常量,是不允许更改的,它们存放在常量区,于是当你做 str+="111"运算的时候,会在内存的常量区再开辟一个空间存放“s111”,并让str指向这个字符串,但是这个str是addStr的局部变量,是另一个指针,与原本的字符串指针没有关系,因此输出的时候还是输出了“s”
最后一个t.addList(strList);也有所不同,他跟String一样是对象,传递时也是传递引用即是指针给方法,而list是允许动态添加数据的,于是你在addList方法里面使用同样指向该strList的指针来操作了真正的strList对象,从而使得方法外部的strList被操作,所以打印时就是List111。
作者:
魏-玉-彪
时间:
2013-11-10 13:29
本帖最后由 魏-玉-彪 于 2013-11-10 13:40 编辑
/**
*
* 为什么int类型和String类型的变量经过方法处理后值没变,而List类型的变量值却变了?
*/
public class Test {
public int addInt(int i) {
return i += 1;
}
//public void addInt(int i) { //首先这里没有返回值
// i += 1;
//}
public void addStr(String str) {
str+="111"; };
public void addList(List<String> strList) {
strList.add("List111");
}
public static void main(String[] args) {
int i = 0;
String str = "s";
List <String> strList = new ArrayList<String>();
Test t = new Test();
//t.addInt(i);
//t.addStr(str); 因为没有反回值 所以这里是多余的,
//假如有返回值,需要调用 对象的方法才有.
System.out.println( t.addInt(i));
System.out.println(i); // 输出0,为什么不是1
System.out.println(str); // 输出s;为什么不是s111
/*事实上,这里输出的是main方法中的变量
因为对象中没有返回值,所以值没有变.而且字符串对象一经创建就不会改变,
除非引用地址改变,而这里的引用地址并没有改变
*/
t.addList(strList);
System.out.println(strList.get(0)); // 输出List111,为什么就是这个可以
//这里ArrayList虽然和String都是引用类型数据,但不同的时,对其操作不会产生新的对象,所以
//处理的是一个对象,不用返回值,仍然影响了ArrayList对象本身.
}
}
复制代码
字符串一经创建就不会改变
举例 String s= "abc"; s的地址是 0X000002;
s=s+"def"; 对不起,这时s的地址指向了新的地址也许是0X007782而 不再是 0X000002
s+"def" 的意思是, 从s地址0X000002找一个 "abc",从"def" 的地址假如是0X999008 找一个"def" 这时,
s地址仍是 0X000002; "def"地址仍是0X999008
ArrayList 不同,假如ArrayList as其地址是 0X8888,
as.add("List111") 后,
as其地址仍然是是 0X8888, 所以,
不用返回值,仍然改变了其中的内容,
而地址没变
作者:
dolphin
时间:
2013-11-10 15:03
你写得这3个,你在它们的方法中,写个输出方法,所有都会如你所想的那样输出。但是你在另一个方法中调用的时候,区别就不一样。
值传递,针对于基本类型,它的最初值
始终不变
,你看成是要其他方法调用此方法时,保持类型一致就行
引用传递,针对于引用类型,它的值是看情况,如果引用地址被操作,则最初值就跟着变化。但是它有一个特例,就是String。
String被定义为final类型的,再传参的时候,和值传递等效。
作者:
月生春
时间:
2013-11-10 15:21
因为Sting类型一旦建立就会在堆内存开辟空间,是不能改变的
作者:
hurryup
时间:
2013-11-10 16:29
一句话,方法中有的,就使用方法中的,没有的则使用被调用方法的。
欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/)
黑马程序员IT技术论坛 X3.2