文章参考了 知乎 的问答,本文重新做了一些梳理。在此给出链接以感谢原作者。
1 数据类型
Java中基础数据类型都是值传递:把数据直接保存在变量里;
引用类型都是引用传递:把对象的地址保存在变量里;
其中,基础类型有八种:
字符类型char
布尔类型boolean
数值类型byte、short、int、long、float、double
需要注意的是String是引用类型。
2 赋值
赋值运算符 =
对于基础数据类型,= 就是把变量中存的数据直接替换掉
对于引用类型,= 也是将变量中的数据替换掉,只不过,替换的地址,而不是真实的对象
3 方法传参
没调用一个方法的时候,都会开辟一个单独的栈空间,用于存储方法中的局部变量,以及方法参数变量。
需要注意的是:给方法参数赋值的时候,是将原数据做一个拷贝,然后再赋值给方法参数的。
public static void methodA(int x, String s){
x = 20;
s = "world";
}
public static void main(String[] args){
int x1 = 10;
String s2 = "hello";
methodA(x1, s1);
system.out.println(x1);
system.out.println(s1);
}
输出的结果是:
10
hello
原因是因为,赋值给方法参数x、s的并不是x1、s1,而是x1/s1的副本,所以正常来说,methodA内部对这个副本做的改动,都不会影响到x1、s1本身;
但是还有一种情况需要注意的是,当方法参数是引用类型,并且,在methodA中,用这个对象的内部方法做修改的时候,结果会是不一样的:
public static void methodA(int x, StringBuilder s){
x = 20;
s.append(" world");
}
public static void main(String[] args){
int x1 = 10;
StringBuilder s1 = new StringBuilder("hello");
methodA(x1, s1);
System.out.println(x1);
System.out.println(s1);
}
上述例子输出的结果是:
10
hello world
原因就是因为,虽然,传递给s的是一个地址的副本,但是这个副本依然是能够指向原来的对象的(此时s和s1都指向同一个对象)。如果调用原对象的自身方法,那么远对象本身也会变化,所以,s1也变化了。
所以,如果你能弄清楚引用的指向问题,就不会弄混这类问题了。
思考一下:如果变成
public static void methodA(int x, StringBuilder s){
x = 20;
s = new StringBuilder("hello");
s.append(" world");
}
public static void main(String[] args){
int x1 = 10;
StringBuilder s1 = new StringBuilder("hello");
methodA(x1, s1);
System.out.println(x1);
System.out.println(s1);
}
这时候会输出什么呢?
答案是:
10
hello
你猜对了吗?