答案:
Java中只有值传递。
针对值类型,传递的是实参的值,对于引用类型,传递的是引用值所存储的地址。
基本概念
1.形参与实参形式参数:在定义函数名和函数体时使用的参数,目的是用来接收调用该函数是传入的参数。
实际参数:在调用有参函数是,主调函数和被调函数之间有数据传递关系。在主调函数中调用一个函数时,函数名后面括号中的参数,称为实际的参数。两者区别:
实参是调用有参方法的时候,真正传递的内容。而形参,是用于接收实参内容的参数。
举例如下:
public static void main(String[] args) {
pt.sout("Hollis");//实际参数为 Hollis}
public static void sout(String name) { //形式参数为 name System.out.println(name);
}
2.值传递与引用传递
上面提到了,当我们调用一个有参函数的时候,会把实际参数传递给形式参数。但是,在程序语言中,这个传递过程中传递的两种情况,即值传递和引用传递。两者的定义如下:
值传递:是指在调用一个有参函数时,会把实际参数复制一份传递到函数中。这样在函数中如果对参数进行修改,将不会影响到实际参数。
引用传递:是指在调用一个有参函数是,直接把实际参数的地址传递到函数中,那么,如果在函数中对参数所进行的修改,将影响到实际参数。
从上面的表述中,可知值传递与引用传递的区别主要有两个:第一,传递的是否是实际参数的地址。第二,函数中对参数进行的修改,是否会影响到实际的参数。
下面,来看一段Java代码:
public static void main(String[] args) {
ParamTest pt = new ParamTest();
User hollis = new User();
hollis.setName("Hollis");
hollis.setGender("Male");
pt.pass(hollis);
System.out.println("print in main , user is " + hollis);
}
public void pass(User user) {
user.setName("hollischuang");
System.out.println("print in pass , user is " + user);
}
最终输出的结果为:
print in pass, userisUser{name='hollischuang', gender='Male'}
print in main , userisUser{name='hollischuang', gender='Male'}
在上面的代码中,由于在函数中对参数进行了修改,影响了实际的user.name的值,所以,很多人认为是进行了引用传递。但是,这种说法是错误的。因为在引用传递的定义中,引用传递的定义是:将实际参数的地址传递到函数中。函数的对参数的修改将影响实际参数的值,是引用传递的结果。并不能根据函数对实际参数的修改,产生了影响就说它是引用传递。之所以在上面那段代码中会产生效果,这和Java语言中一种特殊的类型有关:引用类型。
3.Java中的值类型与引用类型
值类型就是基本数据类型:包括byte、short、int、long、float、double、char、boolean。其中byte、short、int、long是整型。float、double是浮点型,char是字符型,boolean是布尔型。
引用类型:引用其实就像是一个对象的名字或者别名 (alias),一个对象在内存中会请求一块空间来保存数据,根据对象的大小,它可能需要占用的空间大小也不等。访问对象的时候,我们不会直接是访问对象在内存中的数据,而是通过引用去访问。
比如:
String a="This is a Text!";
String b=a;
在Java 虚拟机中对应的是存储状态为:
通过上面的代码和图形示例不难看出,a 和 b 是不同的两个引用,我们使用了两个定义语句来定义它们。但它们的值是一样的,都指向同一个对象 "This is a Text!"。
引用具有以下两个要点:
(1) 引用是一种数据类型(保存在stack中),保存了对象在内存(heap,堆空间)中的地址,这种类型即不是我们平时所说的简单数据类型也不是类实例(对象);
(2) 不同的引用可能指向同一个对象,换句话说,一个对象可以有多个引用,即该类类型的变量。
如下图所示:
在上图中,
当函数形参为值类型时,在传递参数的过程是将变量c和变量d的值,复制给形参a和b.
当函数形参为引用类型时,由于引用类型变量存储的是对象在对堆中的地址。所以,实参 c,d分别指向堆中的地址。在进行参数传递是,c将其指向的地址,复制给对应的形参a,d将其所指向的地址,复制给对应的形参b.这个过成中,传递参数仍然为“复制”的方式。
综上所述,因为Java中只有值传递的方式。由于Java语言中,只有基本类型变量和应用变量这两种,而没有指针类型。所以,会导致参数传递过程对值传递还是引用传递的误解。
Java中只有值传递。针对值类型,传递的是实参的值,对于引用类型,传递的是引用值所存储的地址。
引用类型在List.addAII()中的应用.
在实际的开发过程中,经常会涉及到两个链表的合并。
比如,将list1.addAll(list2),这里的作用就是将list2将入到表list1中。
由于list1.addAll(list2),采用的是值传递。在这个过程中,本质上是将list2中的所有元素的引用复制到list1中。所以,当进行链表合并是,需要注意:
若list2中存储的是不可变元素类型,则将list1.add(list2)之后,修改list2的值,不会影响list1的值。
如果list2存储的是可变类型元素,如Class类型,List、Map等类型是,修改list2的值,会印象list1中的值。
代码演示:list2中存储的是不可变元素类型
// list2 存储不可变元素的情况:
public static void list1AddList2Invariable(){
List list1 = new ArrayList();
List list2 = new ArrayList();
list2.add("hello");
list2.add("world");
list2.add("MeiTuan");
list1.addAll(list2);
System.out.println("list2修改之前");
System.out.println("list1---"+list1);
System.out.println("list2---"+list2);
list2.set(2,"Alibaba");//修改list2中元素的引用
// 修改list2中元素的引用 list.set(index,value) 与 list.get(index).add()
System.out.println("list2修改之后");
System.out.println("list1---"+list1);
System.out.println("list2---"+list2);
}
输出结果为:
list2的修改,并没有印象list1中存储的值。这是因为list2中出处的是不可变类型。
代码演示:list2中存储的是不可变元素类型
public static void list1AddList2VariableII(){
List list1 = new ArrayList<>();
List list2 = new ArrayList<>();
// 对list2进行初始化
for(int i=0;i<6;i++){
list2.add(new Node(i+1));
}
// 执行list1.addAll(list2)
list1.addAll(list2);
// 在修改之前
System.out.println("before data change");
System.out.println(list1.get(1).getValue());
System.out.println(list2.get(1).getValue());
// 对list2进行修改
list2.get(1).setValue(888); // 对引用进行修改
System.out.println("After data change");
System.out.println(list1.get(1).getValue());
System.out.println(list2.get(1).getValue());
}
static class Node{
int value;
public int getValue(){
return value;
}
public void setValue(int value) {
this.value = value;
}
public Node(int value){
this.value = value;
}
}
输出结果:
从上可知,由于list2中存储的是普通的类,而类时可变的类型,所以,list2中元素的改变,会影响到list1。
本文涉及的代码github地址:https://github.com/huifenghechang/three-taste-algorithm/tree/master/src/listgithub.com
参考文章:List集合中add()方法和addAll()方法的区别blog.csdn.netJava引用类型 - 核桃圆 - 博客园www.cnblogs.com为什么说Java中只有值传递。mp.weixin.qq.com