先来看一个简单的Demo
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class Demo45 {
public static void main(String[] args) {
List<Integer> list = new ArrayList<Integer>();
for (int i = 0; i < 10; i++) {
list.add(i);
}
add(list);
for (Integer j : list) {
System.err.print(j+",");
}
System.err.println("*********************");
String a="A";
append(a);
System.err.println(a);
int num = 5;
addNum(num);
System.err.println(num);
}
static void add(List<Integer> list){
list.add(100);
}
static void append(String str){
str+="is a";
}
static void addNum(int a){
a=a+10;
}
}
输出结果
1
2
3
4
0,1,2,3,4,5,6,7,8,9,100,
*********************
A
5
这个时候可能会有疑问了,为什么add方法可以修改List数组,但是append和addNum却没有修改传进来的值
第一步,先搞清楚Java中的基本类型和引用类型的不同之处
1
2
int num = 10;
String str = "hello";
如图所示,num是基本类型,值就直接保存在变量中。而str是引用类型,变量中保存的只是实际对象的地址。一般称这种变量为”引用”,引用指向实际对象,实际对象中保存着内容。
第二步,搞清楚赋值运算符(=)的作用
1
2
num = 20;
str = "java";
对于基本类型 num ,赋值运算符会直接改变变量的值,原来的值被覆盖掉。 对于引用类型 str,赋值运算符会改变引用中所保存的地址,原来的地址被覆盖掉。但是原来的对象不会被改变(重要)。 如上图所示,”hello” 字符串对象没有被改变。(没有被任何引用所指向的对象是垃圾,会被垃圾回收器回收)
第三步,在调用的时候发生了什么
Java 程序设计语言总是采用按值调用。也就是说,方法得到的是所有参数值的一个拷贝,特别是,方法不能修改传递给它的任何参数变量的内容 。
现在再回到最开始的例子,
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
* 首先add方法中的list对象是传入参数的一个拷贝,但是这个拷贝对象指向的是同一个List,所以这个拷
* 象中的add(100)是操作list指向的List数组
*/
add(List<Integer> list)
/**
* str同样是传入字符串的一个拷贝对象,而String是一个finnal修饰的类,也就是无法对其进行修改,所以
* str的+=操作会生成一个新的String对象,也就是拷贝对象变成了一个新的对象,而原str并未发生改变
*/
append(String str)
/**
* 最后这个addNum中传入的是一个Java的基本类型,也就是方法里的a是传入参数的一个拷贝,对a进行操作不
* 会对原数值产生影响
*/
addNum(int a)
这个过程说明:Java 程序设计语言对对象采用的不是引用调用,实际上,对象引用是按值传递的。 下面总结一下 Java 中方法参数的使用情况:
- 一个方法不能修改一个基本数据类型的参数(即数值型或布尔型)。
- 一个方法可以改变一个对象参数的状态 。
- 一个方法不能让对象参数引用一个新的对象。
参考
- Java 到底是值传递还是引用传递?
- Java核心技术;4.5 方法参数