文章参考了 知乎 的问答,本文重新做了一些梳理。在此给出链接以感谢原作者。

1 数据类型

Java中基础数据类型都是值传递:把数据直接保存在变量里;

引用类型都是引用传递:把对象的地址保存在变量里;

image.png

其中,基础类型有八种:

字符类型char

布尔类型boolean

数值类型byte、short、int、long、float、double

需要注意的是String是引用类型。

2 赋值

赋值运算符 =

对于基础数据类型,= 就是把变量中存的数据直接替换掉

image.png

对于引用类型,= 也是将变量中的数据替换掉,只不过,替换的地址,而不是真实的对象

image.png

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也变化了。

image.png

所以,如果你能弄清楚引用的指向问题,就不会弄混这类问题了。

思考一下:如果变成

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

你猜对了吗?