Java 中是引用传递还是值传递,让我们来一探究竟! —— 由 Cool 分享
前言
在学习Java编程语言过程中最容易让你产生误解的问题之一就是 java是值传递还是引用传递。今天就来围绕这个话题揭开迷雾。
概念
首先先来认识一下什么是值传递什么是引用传递。
- 值传递:
- 引用传递:将实际参数的引用传递给该方法,这就是为什么它被引用称为“传递”的原因。
例子分析1
问题:如果java是使用引用传递的话,为什么在函数中 变量的交换会没有卵用呢?
答案:java通过引用来操作对象,并且所有Object类型的变量都是引用一个地址。但是,java传递方法参数并不是引用传递,而是值传递。
来个例子,大家感受一下:
public void badSwap(int var1, int var2)
{
int temp = var1;
var1 = var2;
var2 = temp;
}
当badSwap()方法结束,原先作为实际参数传递进来的变量仍然是它们原来的值,也就是这个方法然无卵用。如果把这个方法的参数由int改变成Object类,结果依然一样。因为java是通过值传递来传递对象引用的。这么说可能不太清晰,再来一个例子。
public void tricky(Point arg1, Point arg2)
{
arg1.x = 100
arg1.y = 100
Point temp = arg1
arg1 = arg2
arg2 = temp
}
public static void main(String [] args)
{
Point pnt1 = new Point(0,0)
Point pnt2 = new Point(0,0)
System.out.println("X: " + pnt1.x + " Y: " +pnt1.y)
System.out.println("X: " + pnt2.x + " Y: " +pnt2.y)
System.out.println(" ")
tricky(pnt1,pnt2)
System.out.println("X: " + pnt1.x + " Y:" + pnt1.y)
System.out.println("X: " + pnt2.x + " Y: " +pnt2.y)
}
构造了两个对象pnt1和pnt2,并且初始的x,y值都是0。之后传入tricky()方
法,在方法中修改行参args1的x,y的值,之后交换行参的指向。
执行main方法 ,输入如下
X: 0 Y: 0
X: 0 Y: 0
X: 100 Y: 100
X: 0 Y: 0
根据输出结果,可以发现实际参数pnt1的值被修改了,pnt2的属性没有变,也就是pnt1盒pnt2的交换失败了!这里最容易被疑惑。
pnt1和pnt2肯定是对象引用,当把pnt1和pnt2传入到tricky()方法当中,
由于java是值传递,也就类似于复制,相当于复制和一个和pnt1一样的行参变量arg1,它也拥有了一个和pnt1变量同一指向的引用。图一展示了通过值传递之后两个引用指向同一个地址。
图1。方法中被传入对象引用参数之后,一个对象至少会有两个引用
上面的例子由于两个变量的引用都指向了同一个对象,所以在方法中修改对象的值会生效。但是由于arg1是copy的一个变量,所以交换的话只是交换了arg1的指向,这就是为什么交换会失败的原因。
图2展示了仅仅是方法参数里的引用交换了,而并不是原始的参数交换。
如果需要成功交换pnt1和pnt2的引用,只能在外部直接修改他们的引用即可。
图2:java通过值传递,copy了一个和pnt1一样的变量,他们拥有同样的引用。在方法调用之后,仅仅是交换了arg1和arg2的引用。
在国内可能有大部分的人清楚传递的规律,但是他们依然习惯是基本类型是值传递,引用类型变量就是引用传递,因为方法中的参数的确有了外部变量的引用。这个看个人理解。我更偏向于是值传递:通过值传递之后方法里的参数拥有了和实际参数一样的值(基础类型为值,对象类型为引用),所以才拥有了引用。而如果是引用传递的话,那就是是直接传递一个存放于堆区的对象给(也就是直是复制了一个对象)。当然这只是我个人的认识。
例子分析2
public class Test {
private static int a;
private int b;
public static void main(String[] args) {
System.out.println(a);
modify(a);
System.out.println(a);
return;
}
private static void modify(int a) {
a++;
}
}
知道了java是值传递的,结果很清楚了
输出a的值肯定不变。
java总是通过值传递而不是引用传递,再来一个例子
例子分析3
public class Balloon {
private String color;
public Balloon(){}
public Balloon(String c){
this.color=c;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
}
Balloon类拥有一个color属性。
public class Test {
public static void main(String[] args) {
Balloon red = new Balloon("Red");
Balloon blue = new Balloon("Blue");
swap(red, blue);
System.out.println("red color="+red.getColor());
System.out.println("blue color="+blue.getColor());
foo(blue);
System.out.println("blue color="+blue.getColor());
}
private static void foo(Balloon balloon) {
balloon.setColor("Red");
balloon = new Balloon("Green");
balloon.setColor("Blue");
}
public static void swap(Object o1, Object o2){
Object temp = o1;
o1=o2;
o2=temp;
}
}