要理解这个问题,首先要清楚java中变量保存的是什么。
java中包括八个基本类型 :
整数:byte short int long
浮点型:float double
布尔型:boolean
字符:char
对于这八个基本类型,保存的都是值,所以对于一个int a=1;的code,会在heap中声明一个a的变量,它保存的值是1。而对于其他的对象类型,比如String str = new String("string");会先在内存里创建一个“string”的对象,然后再创建一个str的对象,并把“string”的地址赋给str,所以str保存的就是一个指针。
明白了java的变量的保存方式,就很容易明白以上的问题了。对于通常所说的传值,也就是把基本类型的“值”传过去,对象类型的指针传过去,因为对象类型的指针也是变量保存的一个值。这种说法其实和传引用本质上是一样的。只要明白了以上细节,就很容易理解了。
对于对象类型,在没有经过重新赋值之前,指针指向的变量都是传入之前的那个对象,所以对它进行的修改也会影响到所有指向这个对象的变量。但是经过重新赋值以后,那么这个指针就不是指向以前的对象了,所以做任何修改,都不会影响到之前的变量。
举个例子:
public class Tmp {
void f(Integer aa){
aa = 2;
}
void g(){
Integer a = new Integer(10);
f(a);
System.out.println(a);
}
void k(StringBuffer sba){
sba.append("aa");
}
void kk(){
StringBuffer sb = new StringBuffer("sb");
k(sb);
System.out.println(sb);
}
void s(String s){
//s += "ss";
s = s.replaceAll("r","t");
System.out.println(s);
}
void ss(){
String string = new String("String");
s(string);
System.out.println(string);
}
public static void main(String args[]){
Tmp t = new Tmp();
t.g();
t.kk();
t.ss();
}
}
运行结果:
10
sbaa
Stting
String
对于Integer,没有可以改变值得方法,所以aa=2会重新初始化一个2的Integer Object,把aa的指针指向它,而a还是指向10的那个变量.
对于StringBuffer,提供了一个append,而sba和sb都是指向"sb"这个StringBuffer的对象,所以对sba做的改变也会影响到sb这个对象.
对于string对象,和StringBuffer一样,但是它是一个final类,也没有提供一个改变自己的方法,所以s.replaceAll("r","t");返回的是一个新的string对象,当前s和string还是都指向的"string"这个字符串,但是s = s.replaceAll("r","t");这句话就把s重新指向了新生成的那个对象.
java中包括八个基本类型 :
整数:byte short int long
浮点型:float double
布尔型:boolean
字符:char
对于这八个基本类型,保存的都是值,所以对于一个int a=1;的code,会在heap中声明一个a的变量,它保存的值是1。而对于其他的对象类型,比如String str = new String("string");会先在内存里创建一个“string”的对象,然后再创建一个str的对象,并把“string”的地址赋给str,所以str保存的就是一个指针。
明白了java的变量的保存方式,就很容易明白以上的问题了。对于通常所说的传值,也就是把基本类型的“值”传过去,对象类型的指针传过去,因为对象类型的指针也是变量保存的一个值。这种说法其实和传引用本质上是一样的。只要明白了以上细节,就很容易理解了。
对于对象类型,在没有经过重新赋值之前,指针指向的变量都是传入之前的那个对象,所以对它进行的修改也会影响到所有指向这个对象的变量。但是经过重新赋值以后,那么这个指针就不是指向以前的对象了,所以做任何修改,都不会影响到之前的变量。
举个例子:
public class Tmp {
void f(Integer aa){
aa = 2;
}
void g(){
Integer a = new Integer(10);
f(a);
System.out.println(a);
}
void k(StringBuffer sba){
sba.append("aa");
}
void kk(){
StringBuffer sb = new StringBuffer("sb");
k(sb);
System.out.println(sb);
}
void s(String s){
//s += "ss";
s = s.replaceAll("r","t");
System.out.println(s);
}
void ss(){
String string = new String("String");
s(string);
System.out.println(string);
}
public static void main(String args[]){
Tmp t = new Tmp();
t.g();
t.kk();
t.ss();
}
}
运行结果:
10
sbaa
Stting
String
对于Integer,没有可以改变值得方法,所以aa=2会重新初始化一个2的Integer Object,把aa的指针指向它,而a还是指向10的那个变量.
对于StringBuffer,提供了一个append,而sba和sb都是指向"sb"这个StringBuffer的对象,所以对sba做的改变也会影响到sb这个对象.
对于string对象,和StringBuffer一样,但是它是一个final类,也没有提供一个改变自己的方法,所以s.replaceAll("r","t");返回的是一个新的string对象,当前s和string还是都指向的"string"这个字符串,但是s = s.replaceAll("r","t");这句话就把s重新指向了新生成的那个对象.