首页 > 试题广场 > 在java中为什么很多人说有值传递和引用传递?引用传递的本质
[问答题]
在java中为什么很多人说有值传递和引用传递?引用传递的本质是什么?

首先,不要纠结于 Pass By Value 和 Pass By Reference 的字面上的意义,否则很容易陷入所谓的“一切传引用其实本质上是传值”这种并不能解决问题无意义论战中。
更何况,要想知道Java到底是传值还是传引用,起码你要先知道传值和传引用的准确含义吧?可是如果你已经知道了这两个名字的准确含义,那么你自己就能判断Java到底是传值还是传引用。
这就好像用大学的名词来解释高中的题目,对于初学者根本没有任何意义。

一:搞清楚 基本类型 和 引用类型的不同之处

int num = 10;
String str = "hello";

图片说明

如图所示,num是基本类型,值就直接保存在变量中。而str是引用类型,变量中保存的只是实际对象的地址。一般称这种变量为"引用",引用指向实际对象,实际对象中保存着内容。

二:搞清楚赋值运算符(=)的作用

num = 20;
str = "java";

对于基本类型 num ,赋值运算符会直接改变变量的值,原来的值被覆盖掉。
对于引用类型 str,赋值运算符会改变引用中所保存的地址,原来的地址被覆盖掉。但是原来的对象不会被改变(重要)。
如上图所示,"hello" 字符串对象没有被改变。(没有被任何引用所指向的对象是垃圾,会被垃圾回收器回收)
图片说明
三:调用方法时发生了什么?参数传递基本上就是赋值操作。
第一个例子:基本类型

void foo(int value) {
    value = 100;
}
foo(num); // num 没有被改变

第二个例子:没有提供改变自身方法的引用类型

void foo(String text) {
    text = "windows";
}
foo(str); // str 也没有被改变

第三个例子:提供了改变自身方法的引用类型

StringBuilder sb = new StringBuilder("iphone");
void foo(StringBuilder builder) {
    builder.append("4");
}
foo(sb); // sb 被改变了,变成了"iphone4"。

第四个例子:提供了改变自身方法的引用类型,但是不使用,而是使用赋值运算符。

StringBuilder sb = new StringBuilder("iphone");
void foo(StringBuilder builder) {
    builder = new StringBuilder("ipad");
}
foo(sb); // sb 没有被改变,还是 "iphone"。

重点理解为什么,第三个例子和第四个例子结果不同?

下面是第三个例子的图解:
图片说明
builder.append("4")之后
图片说明
下面是第四个例子的图解:
图片说明
builder = new StringBuilder("ipad"); 之后
图片说明

作者:Intopass
链接:https://www.zhihu.com/question/31203609/answer/50992895
来源:知乎
著作权归作者所有,转载请联系作者获得授权。

编辑于 2017-05-05 12:58:56 回复(22)
public void add(int a) { int b = a; } 这个可以看作是值传递,a是基本数据类型,他把他的值传给了b public void add(Object obj) { Object objTest = obj; } 这个可以看作是址传递,obj是引用数据类型,是把他栈中指向堆中的对象的地址值赋值给了objTest. 这时候就同时有两个引用指向了堆中的某个Object对象 其实这样看来,java应该只有值传递的。如果是基本数据类型,传递的就是实际的值. 如果是引用数据类型,传递的就是该引用的地址值.
发表于 2016-04-13 11:26:12 回复(4)
值传递是指将值的副本传递给调用的函数,调用的函数可以改变副本的值,但是并不会影响main函数中的原值。 引用传值,传递的是对象的引用,同一个引用指向相同的实体,所以改变引用指向实体的值,可以影响main函数中实体的值。
发表于 2015-11-21 16:24:30 回复(2)
值传递(pass by value)是指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。
引用传递(pass by reference)是指在调用函数时将实际参数的地址直接传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数。
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 = new User();
   user.setName("hollischuang");
   user.setGender("Male");
   System.out.println("print in pass , user is " + user);
}

上面的代码中,我们在pass方法中,改变了user对象,输出结果如下:

print in pass , user is User{name='hollischuang', gender='Male'}  print in main , user is User{name='Hollis', gender='Male'}
像上面代码就证明了JAVA中的得对象传递也是值传递,并非引用传递。
解析:
如果是引用传递,那么在pass()函数中的 user = new User()这段代码中,user的地址改变了,
那么应该main函数中holis对象的地址也会变,在pass中改变了user对象中name成员的值,holis对象的应该也改变了,但是并没有。
这里就证明了pt.pass(holis)调用pass()函数是把holis的地址复制了一份,在传给形参的。
再次强调:并不是传递了地址就是引用传递,是否是引用传递是看是否有复制一份值,然后把复制的传个形参。

  ***这里是被牛客网屏蔽了,搞不懂,***为x/p/

发表于 2018-10-03 00:15:03 回复(4)
java中对象作为参数传递给一个方法,到底是值传递,还是引用传递?
   值传递!Java中只有按值传递,没有按引用传递!
   这个解释不是一两句话能够清晰解释的。
   搜了半天发现这篇还有点用http://guhanjie.iteye.com/blog/1683637

发表于 2016-03-08 23:06:47 回复(10)
值传递,顾名思义传递的是其值,也可以理解为副本给你,任意修改,原本不变。 引用传递,顾名思义传递本身,或者说传递的是地址,修改的是本身或者是原本地址里的内容。 值传递,原本不改变,引用传递,原本改变
发表于 2016-08-19 09:44:17 回复(0)
public static void main(String[] args) {  
   StringBuilder x = new StringBuilder("ab");  
   change(x);  
   System.out.println(x);  
}  
  
public static void change(StringBuilder x) {  
   x = new StringBuilder("cd");
}

输出ab


  1. public   static   void  main(String[] args) {  
  2.     StringBuilder x = new  StringBuilder( "ab" );  
  3.     change(x);  
  4.     System.out.println(x);  
  5. }  
  6.    
  7. public   static   void  change(StringBuilder x) {  
  8.     x.delete(0 2 ).append( "cd" );  
  9. }
输出cd


  1. public   static   void  main(String[] args) {  
  2.     String x = new  String( "ab" );  
  3.     change(x);  
  4.     System.out.println(x);  
  5. }  
  6.    
  7. public   static   void  change(String x) {  
  8.     x = "cd" ;  
输出ab


核心:

5、这个问题的解决方法


如果我们真的需要改变对象的值。首先,对象应该是可变的,例如,StringBuilder对象。其次,我们需要确保没有创建新的对象并将此对象分配给参数变量,因为Java是只是按值传递(passing-by-value)。


参考自 http://blog.csdn.net/wuwenxiang91322/article/details/17038557
发表于 2016-08-24 23:05:11 回复(2)
值传递是传递了原有对象的一个副本,所以调用函数可以改变副本的值,但是对原有对象没有任何影响 引用传递是传递了对象的引用,对引用的操作会改变源对象本身
JAVA只有值传递!!
发表于 2017-03-26 13:24:30 回复(1)

基本数据类型的传递为值传递,对象之间的传递为引用传递。

发表于 2019-10-25 08:41:29 回复(1)
public void add(int a) { int b = a; } 这个可以看作是值传递,a是基本数据类型,他把他的值传给了b public void add(Object obj) { Object objTest = obj; } 这个可以看作是址传递,obj是引用数据类型,是把他栈中指向堆中的对象的地址值赋值给了objTest. 这时候就同时有两个引用指向了堆中的某个Object对象 其实这样看来,java应该只有值传递的。如果是基本数据类型,传递的就是实际的值. 如果是引用数据类型,传递的就是该引用的地址值.
发表于 2017-02-19 10:55:25 回复(0)
值传递是传递了原有对象的一个副本,所以调用函数可以改变副本的值,但是对原有对象没有任何影响 引用传递是传递了对象的引用,对引用的操作会改变源对象本身
发表于 2016-03-04 18:48:29 回复(0)

8大基本类型都属于值传递,方法内对其进行修改是不会改变实际参数的。引用类型传递时则是传递的是一个地址值,这时就可以对该地址的值进行修改,再次访问得到的是修改后的值。

而string是不可改变的。

发表于 2019-12-19 11:54:38 回复(0)
java指针问题!重点!
发表于 2019-10-14 19:20:15 回复(0)

值传递,一般传的是基础数据类型,引用传递传的是实例对象地址

发表于 2019-05-11 08:30:37 回复(0)
值传递传递的是变量的副本,也就是它的复制;而引用传递传递的是对象的指针。 例如在方法中传入参数,如果传入的是实例变量,则进行的是值传递,在方法中改变的是这个实例对象的副本,并不会对实例对象本身造成影响。 而如果传入的是一个对象,则进行的是引用传递,传递的是该对象的指针。在方法中对指针的操作依然是对原对象的操作,改变的是原对象的状态
发表于 2016-05-09 00:07:55 回复(0)
没有引用传递吧
发表于 2016-03-28 09:24:21 回复(0)
值传递指的是在方法调用时,传递的参数是按值的拷贝传递。引用传递指的是在方法调用时,传递的参数是变量所对应的内存空间的地址。
发表于 2016-02-09 18:39:02 回复(0)
就Java而言,参考答案中的对象不是指堆内存中的那个对象,差点被误导。
发表于 2016-01-21 19:20:59 回复(0)
<p>值传递指的是传递副本给调用的函数,不会改变原值,引用传递指的是传递对象的地址,会改变原来的对象</p>
发表于 2020-12-07 01:11:08 回复(0)
<p>值传递对于基本数据类型来说,传递的是一个副本,改变副本不改变原数据</p><p>引用传递通常传递的是一个地址,对引用对象操作,也会改变原对象</p>
发表于 2020-11-30 15:26:05 回复(0)