【JavaSE】Java到底是值传递还是引用传递?
文章目录
- 【JavaSE】Java到底是值传递还是引用传递?
- 一:基本数据类型和引用数据类型区别
- 二:案例
- 1:传递基本类型
- 2:传递引用类型
- 三:引用传递是怎么样的?
- 四:为什么 Java 不引入引用传递呢?
- 五:总结
一:基本数据类型和引用数据类型区别
我们来看看基本数据类型和引用数据类型之间的差别。
int age = 18;
String name = "二哥";
age 是基本类型,值就保存在变量中,而 name 是引用类型,变量中保存的是对象的地址。一般称这种变量为对象的引用,引用存放在栈中,而对象存放在堆中。
这里说的栈和堆,是指内存中的一块区域,和数据结构中的栈和堆不一样。栈是由编译器自动分配释放的,所以适合存放编译期就确定生命周期的数据;而堆中存放的数据,编译器是不需要知道生命周期的,创建后的回收工作由垃圾收集器来完成。
当用 = 赋值运算符改变 age 和 name 的值时。
age = 16;
name = "三妹";
对于基本类型 age,赋值运算符会直接改变变量的值,原来的值被覆盖。
对于引用类型 name,赋值运算符会改变对象引用中保存的地址,原来的地址被覆盖,但原来的对象不会被覆盖。
二:案例
1:传递基本类型
class PrimitiveTypeDemo {
public static void main(String[] args) {
int age = 18;
modify(age);
System.out.println(age);
}
private static void modify(int age1) {
age1 = 30;
}
}
1)main()
方法中的 age 为基本类型,所以它的值 18 直接存储在变量中。
2)调用 modify()
方法的时候,将会把 age 的值 18 复制给形参 age1。
3)modify()
方法中,对 age1 做出了修改。
4)回到 main()
方法中,age 的值仍然为 18,并没有发生改变。
如果我们想让 age 的值发生改变,就需要这样做。
class PrimitiveTypeDemo1 {
public static void main(String[] args) {
int age = 18;
age = modify(age);
System.out.println(age);
}
private static int modify(int age1) {
age1 = 30;
return age1;
}
}
第一,让 modify()
方法有返回值;
第二,使用赋值运算符重新对 age 进行赋值。
2:传递引用类型
就以 String 为例吧。
class ReferenceTypeDemo {
public static void main(String[] args) {
String name = "二哥";
modify(name);
System.out.println(name);
}
private static void modify(String name1) {
name1 = "三妹";
}
}
在调用 modify()
方法的时候,形参 name1 复制了 name 的地址,指向的是堆中“二哥”的位置。
当 modify()
方法调用结束后,改变了形参 name1 的地址,但 main()
方法中 name 并没有发生改变。
三:引用传递是怎么样的?
看到这里,相信你已经知道了 Java 中只有值传递,是没有引用传递的。 但是,引用传递到底长什么样呢?下面以 C++
的代码为例 。
#include <iostream>
void incr(int& num)
{
std::cout << "incr before: " << num << "\n";
num++;
std::cout << "incr after: " << num << "\n";
}
int main()
{
int age = 10;
std::cout << "invoke before: " << age << "\n";
incr(age);
std::cout << "invoke after: " << age << "\n";
}
输出结果:
invoke before: 10
incr before: 10
incr after: 11
invoke after: 11
分析:可以看到,在 incr
函数中对形参的修改,可以影响到实参的值。要注意:这里的 incr
形参的数据类型用的是 int&
才为引用传递,如果是用 int
的话还是值传递哦!
四:为什么 Java 不引入引用传递呢?
引用传递看似很好,能在方法内就直接把实参的值修改了,但是,为什么 Java 不引入引用传递呢?
- 出于安全考虑,方法内部对值进行的操作,对于调用者都是未知的(把方法定义为接口,调用方不关心具体实现)。你也想象一下,如果拿着银行卡去取钱,取的是 100,扣的是 200,是不是很可怕。
- Java 之父 James Gosling 在设计之处就看到了 C、C++ 的许多弊端,所以才想着去设计一门新的语言 Java。在他设计 Java 的时候就遵循了简单易用的原则,摒弃了许多开发者一不留意就会造成问题的“特性”,语言本身的东西少了,开发者要学习的东西也少了。
五:总结
Java 中将实参传递给方法(或函数)的方式是 值传递 :
- 如果参数是基本类型的话,很简单,传递的就是基本类型的字面量值的拷贝,会创建副本。
- 如果参数是引用类型,传递的就是实参所引用的对象在堆中地址值的拷贝,同样也会创建副本。