Java 的参数传递

一、传值和传址(引用)

Java 的参数传递分为传递基本数据类型(传值)和传递引用数据类型(传址)

public class Demo {

public void fun(Test test, int i) {
test.name = "test2";
i = 2;
System.out.println(i);
}

public static void main(String[] args) {
Demo demo = new Demo();
Test test = new Test();
int i = 1;
demo.fun(test, i);
System.out.print(test.name + " and " + i);
}
}

class Test {
String name = "test";
}
2
test2 and 1

对于基本数据类型,当我们修改传递的值,原来的值不会改变,所以传递的是值的拷贝。值的拷贝在一块儿新的内存中。

对于引用数据类型,当我们通过传递的引用变量修改对象的属性,原引用指向的对象也将改变,所以没有将对象的数据拷贝传递,传递的是指向对象的引用变量,即对象的地址。当然,引用变量是值传递,引用变量的拷贝在一块儿新的内存中。

正常来说,传值更符合正常思路。我把值传给你,你使用它,不会影响我的值。

因为传址的特点,可以将大数据存放到对象中,传递对象引用,减少参数(局部变量表)的大小以提高栈帧的空间利用率。

二、String 的参数传递

public class Demo {

String str = new String("hello");
char[] ch = {'a', 'b', 'c'};

public void fun(String str, char[] ch) {
str = "world";
ch[0] = 'd';
}

public static void main(String[] args) {
Demo demo = new Demo();
demo.fun(demo.str, demo.ch);
System.out.print(demo.str + " and ");
System.out.print(demo.ch);
}
}
hello and dbc
  1. 对象 test 调用 fun 方法,将实参 test.str(全局变量 str 存放对象 “hello” 的内存地址)和 test.ch(全局变量 ch 存放字符数组对象的内存地址),传给 fun 方法的形参 str 引用和 ch 引用。

  2. 局部变量 str 存放对象 “hello” 的内存地址。"world" 匿名对象, str = "world"; 等价于 str = new String("world") ,相当于将在堆中重新分配一个内存空间存放 “world”,局部变量 str 指向 “world”。局部变量 str 的生命周期和方法相同,只是名称和全局变量 str 相同。

以上两步操作在 JVM 中如下图所示,内存地址为假设。

image

  1. char ch[] 与 char[] ch 等价。语句 ch[0] = 'd'; 将替换字符数组对象中下标为 0 的字符,即改变了对象的内容。test.str 没有改变,还是 “hello”,test.ch 从 “abc” 改为 “dbc”。

IDEA 调试图如下:

image

2.1、理解引用存放地址

Book a == new Book();// 对象 1
Book b == new Book();// 对象 2
b = a;

问:那个对象会被回收?
答:对象 2,因为将引用 a 中存放对象 1 的地址赋值给了引用 b,所以引用 b 将 “指向” 对象 1,对象 2 将被回收。

三、总结

可以将地址视为值,所以传值和传址都可以视为传值。

四、延伸阅读

Depp Wang wechat
个人公众号