JAVA值传递与地址传递

关于

java刚开始的时候,除了基本类型的参数传递叫值传递外,其他类型的也都叫引用传递(有java旧版教材的都应该看到过),只是最近不知道什么原因,开始有鼓吹没有引用传递了
其实,引用传递一开始是针对C的引用类型而言的,引用传递以外,有值传递和地址传递两种(即传值和传址),因为引用传递和地址传递都能达到改变形参外的实参的效果,所以,慢慢的地址传递也开始被很多人叫为引用传递。
形参的形就是一种所谓的形式,只是用于辅助说明函数的参数的类型,并没有实际的值,当函数被调用时,函数栈产生,形参也就存在于该栈的数据区(其实就是一个相对地址),当函数调用结束,栈撤销,形参也没了。实参是函数调用时实际传给函数的参数,值传递时,实参的值被复制到函数栈的形应的形参的数据区的地址里,地址(引用)传递时,实参的地址被复制到函数栈的形应的形参的数据区的地址里,函数对形参的操作,只是针对与数据区的那个形参的地址而操作,值传递时,因为修改的是形参地址的内容,所以不会对实参产生影响,地址(引用)传递时,修改形参的属性,并不是直接就把形参的地址里的内容覆盖(因为形参地址里存的只是个地址,没有什么属性),而是先从形参地址里取出里面的内容,即形参和实参共同指向的地址,然后再对那个地址进行操作,这样,因为实参也指向那个地址,所以实参的属性也会发生改变。对于重新给形参赋值,这时是在形参的地址里重新存入一个新的地址,此时形参与实参不再指向同一个地址,所以形参的任何变化都不会对实参造成影响。这也就是为什么在函数里不能改变实参的指向的原因。

问题

首先看看代码:

public class Test {
	 public static void main(String[] args) {
	        String str = "123";
	        System.out.println(str);
	        change(str);
	        System.out.println(str);
	    }
    public static void change(String str){
    		str = "456";
    }
}

那么你觉得会输出多少呢?至少我曾经觉得是:

123
456

但是,正确答案是:

123
123

这是为什么呢?我相信答错的同学大都是受到了一些”java教材“的影响–java的参数传递有两种:

  1. 值传递,传递值,在函数中形参发生的变化不影响实参。
  2. 引用传递,传递对象引用,在函数中形参发生的变化影响实参。

然而,实际上java参数传递只有一种情况,那就是值传递。所不同的是,一般说的"引用传递",在实际中传递的不过是引用对象的地址值

在解释上述代码前,先要在补充一点知识:

String a = new String("123");
String b;
b= new String("123");

两种形式的代码所形成的的结果是完全一致的,后面一种更容易理解java中的引用与对象的具体含义。

先声明一个String对象的引用,再new一个“123”对象,最后将这个对象赋值(等号=)给该引用。

  1. b:对象的引用
  2. “123”:实际对象

好了,现在来具体解释一下值传递和地址值引用吧。

1.值

int a = 1;
void f(int b){
  b =2;
}

a是多少呢?肯定是1嘛。

graph LR
1-->?
graph LR
A--> B

将a的值1传递给b,b的值为1.这样不论b如何更改,并不影响a的值。

2.地址值

String a = new String("123";)
void main(String b){
  b = new String("345");
}
graph LR
a--> 123
graph LR
b--> 123

首先,a将对象“123”的地址值传递给b,b指向"123"的地址。之后 new了一个"345"对象,b重新指向了"345",也就是下图。

graph LR
a--> 123
graph LR
b--> 456

所以,仅仅是b的引用对象发生了变化,a的引用对象毫无改变。

public class Test {
	 public static void main(String[] args) {
		 StringBuilder a = new StringBuilder("123");
		 change(a);
		 System.out.println(a);
	    }
    public static void change(StringBuilder str){
    		str.append("345");
    }
}

现在,a的值是多少?

123345

这也就是平常我们所理解的,传递“引用”会影响原对象本身。还是画个图来解释:解释
首先a将“123”对象的地址传递给b,b指向“123”,接着通过“绿色”引用改变了“123”对象。因为a也是指向“123”对象,所以输出a也变为了"123345"。