前言
Java的参数传递是值传递还是引用传递?还是两者都有?
先说结论:Java语言总是采用按值传递。
举例说明
在Java中,方法的参数共有两种类型:
- 八种基本数据类型(数字、布尔值)
- 对象引用
对于方法参数传递基本数据类型,Java传递的值是对该基本数据的值的拷贝x,这个拷贝x在方法内无论如何修改都不能改变实际参数的值,这种参数传递的方式大家都很熟悉,这就是按值传递。看代码:
public static void main(String[] args){
int y = 10;
doSome(y);//y的值仍然为10
System.out.println(y);//y=10
}
public static void doSome(int x){
x = x * 3;//x从10变为了30
}
对于对象的引用,本质上方法传递的对象引用的拷贝,对象引用和引用的拷贝同时引用同一个对象,因此这个拷贝指向了对象,这个拷贝可以改变对象的状态(看下面第一段代码),但是这种改变是因为方法传递的是对象引用的值的拷贝,与C++的引用传递不同,Java中的形参的改变并不是实际参数的改变,而是拷贝的地址值所指向的对象的改变。看代码:
//定义一个测试类
static class People{
private String name;
private int age;
//省略构造方法和Get,Set方法和toString方法
}
public static void main(String[] args){
People tom = new People("Tom", 10);
System.out.println(tom.getAge());//10
doSome(tom);
System.out.println(tom.getAge());//15
//通过doSome方法可以修改对象的状态,但这不是引用传递所起的作用
//而是值传递拷贝了地址值,拷贝值共用了同一个对象
}
public static void doSome(People tom) {
tom.setAge(15);
}
下面举一个例子来说明对象引用是通过值传递来传递参数的例子。
假设Java方法传递对象引用时是通过按引用传递来传递对象引用的,那么在方法中交换对象a和对象b之后,方法外的实际参数应该也会交换对象(也就是说形参的操作会影响实际参数的操作),可是编写实际代码之后可以发现,在方法中交换了对象之后,并没有交换原来对象。看代码:
public static void main(String[] args){
People tom = new People("Tom", 10);
People jack = new People("Jack", 20);
System.out.print("doSome之前:");
System.out.println("tom:"+tom.toString() +". jack:"+jack.toString());
doSome(tom,jack);
System.out.print("doSome之后:");
System.out.println("tom:"+tom.toString() +". jack:"+jack.toString());
}
public static void doSome(People a,People b) {
People x = a;
a = b;
b = x;
}
输出结果:
可以看出,形参的操作并没有影响到实参,所以这里并不是按引用传递的方式!
下面的图可以具体演示一下上面的过程:
从上面这张图来说,我们能够改变对象的状态(属性值等),是因为通过按值传递的方式拷贝了对象的引用。而当我们通过在方法中交换两个对象的引用时,方法中的两个值拷贝的对象确实能够进行交换操作,但是这对传入方法之前的实际参数并没有产生实际的影响。
总结
综上,我们才会说Java方法传递的方式是按值传递。