hollischuang / toBeTopJavaer

To Be Top Javaer - Java工程师成神之路
https://www.hollischuang.com
25.36k stars 5.47k forks source link

值传递和引用传递(混淆试听了) #14

Closed crazyyj closed 4 years ago

crazyyj commented 5 years ago

一个是set的内部值 一个已经是改变对象本身,当然不是了。 如果在pass 中new User 当然 不是同一个对象 public void pass(String a){ a = "afds"; String a = new String("新的string"); } 是同一个意思。你重置了对象。

XIEJD commented 5 years ago

感觉,绕了一大圈,就是说对象的引用 也是值的一种 🤣。

inRush commented 5 years ago

我觉得按他那样说,好像没有语言是引用传递的了,都是值传递了, 引用传递的定义是指调用函数时将实际参数的地址直接传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数。 例子中的图的确也是把传递地址进去了,也就是user指向了hollis的地址,后面new操作把user指向的地址给改了,那接下来的修改当然和外面的hollis没关系了。虽然地址本身也是一个值,但是我们用的不是这个地址,而是地址所指向的内容啊。 我对引用传递和值传递定义的理解是这样的,如果传递过来的值是我们需要的内容本身,那么就是值传递,需要拷贝一份需要的值,也就是内容本身;如果传递过来的是内容地址,需要拷贝的是地址的值,不是内容本身,那么就是引用传递。

PadalNOTD commented 5 years ago

从我初学者看来,整个文章的引用是有两个意思的 没说java的变量内存分配之前就来说值传递和引用传递不太好办吧,java变量的内存管理也算是语言特

nanhuaqq commented 5 years ago

我觉得按他那样说,好像没有语言是引用传递的了,都是值传递了, 引用传递的定义是指调用函数时将实际参数的地址直接传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数。 例子中的图的确也是把传递地址进去了,也就是user指向了hollis的地址,后面new操作把user指向的地址给改了,那接下来的修改当然和外面的hollis没关系了。虽然地址本身也是一个值,但是我们用的不是这个地址,而是地址所指向的内容啊。 我对引用传递和值传递定义的理解是这样的,如果传递过来的值是我们需要的内容本身,那么就是值传递,需要拷贝一份需要的值,也就是内容本身;如果传递过来的是内容地址,需要拷贝的是地址的值,不是内容本身,那么就是引用传递。

我同意你的观点, 不同意作者的观点, 我们举c语言的例子, c语言里有“值传递”和“址传递” function add(&var1, &var2) 如作者所描述 那么也是值传递。所以我觉得作者理解有误差

wangruyu1 commented 5 years ago

虽然不知道你们在说啥,我的理解可以参考下: 1.java都是值传递. 2.引用传递存在,c语言的引用传递就是。引用传递相当于给变量起一个别名,并不是新建一个变量。

inRush commented 5 years ago

@wangruyu1 我后面查了下C语言的引用,然后再回过头来看这篇文章,确实是我的理解有偏差 下面是c++引用的例子:

void swap(int& x, int& y)
{
   int temp;
   temp = x; /* 保存地址 x 的值 */
   x = y;    /* 把 y 赋值给 x */
   y = temp; /* 把 x 赋值给 y  */

   return;
}
int main ()
{
   // 局部变量声明
   int a = 100;
   int b = 200;

   cout << "交换前,a 的值:" << a << endl;
   cout << "交换前,b 的值:" << b << endl;

   /* 调用函数来交换值 */
   swap(a, b);

   cout << "交换后,a 的值:" << a << endl;
   cout << "交换后,b 的值:" << b << endl;

   return 0;
}

输出:

交换前,a 的值: 100
交换前,b 的值: 200
交换后,a 的值: 200
交换后,b 的值: 100

Java是没办法做到这样的

Agoni1 commented 5 years ago

@inRush 我得到的结果与你相反 image

inRush commented 5 years ago

@Agoni1 形参要加&,你看下我的代码,加上&才行

Agoni1 commented 5 years ago

@inRush 你的意思是我写错了?我不懂c语言,照着文档写的,应该没问题吧,反而是你的代码没法运行

inRush commented 5 years ago

@Agoni1 那是c++,和c语言是有点区别的 image

Agoni1 commented 5 years ago

@inRush 百度了一下,搞清楚了,参考https://blog.csdn.net/tianwei0822/article/details/78921823。 说到底还是博主说错了,java引用类型和c++的引用根本不是一回事,或者说语言内部的处理机制不同。但是博主说java引用传递本质是值传递,这种说法有问题的

inRush commented 5 years ago

@Agoni1 这个怎么说呢,其实理解了是怎么回事就行,是不是值传递也没啥所谓的,一个说法而已

inRush commented 5 years ago

不过你给的那篇博文也说的很清楚了,java的引用其实是相当于c++的指针,也的确是,因为它们的行为是很类似的,所以相对于C++来说,Java的这个也不算引用传递,不过对于Java本身,说这个是引用传递也行吧,每个人的理解都不同,没必要纠结,多学点才是最重要的。

ecit13218 commented 5 years ago

java只有值传递,各位可以参考下 Java 到底是值传递还是引用传递? - Intopass的回答 - 知乎 https://www.zhihu.com/question/31203609/answer/50992895

LiuZHolmes commented 5 years ago

不过你给的那篇博文也说的很清楚了,java的引用其实是相当于c++的指针,也的确是,因为它们的行为是很类似的,所以相对于C++来说,Java的这个也不算引用传递,不过对于Java本身,说这个是引用传递也行吧,每个人的理解都不同,没必要纠结,多学点才是最重要的。

我赞成这个观点。就比如,在Java里传参时如果参数是个对象,那么Java会把对象的地址作为值传递,所以说是按值传递。(我没记错的话)如果是在C++里,参数是对象的话,C++会把对象的拷贝作为值传递,这也是按值传递,叫法一样但行为不一致。C++里与前面Java行为一致的是把对象作为引用传递,其实就是传递对象的地址,但这里叫按引用传递。

所以说,如果从传递的宾语的角度来说,作者的解析就是正确的。只是理解的时候如果要观察实际的结果的话,还要考虑语言自己的行为。在Java里,对象的地址就是值,所以就是按值传递。在C++里,对象作为引用才传递地址,所以就是按引用传递。

imchenway commented 5 years ago

准确的说,是值的引用传递

walkkong commented 4 years ago

作者的理解没有问题呀。区别就在于有没有副本,是直接使用本身还是使用拷贝值。

luo-zhan commented 4 years ago

引用传递和值传递的根本区别是传参时是否进行了拷贝。

其实c或c++的方法申明就很清晰,形参前有&符号就是引用传递,没有&符号就是值传递,前者引用传递的时候,入参直接重新赋值也是会改变外部变量的,而后者值传递的时候,即使入参是List,对其add新元素也不会对外部变量产生影响(因为重新拷贝了一份list),这个大家写个例子就能证明。

再回头看下java,发现他们的区别了吗,如果java是引用传递,那么在方法内对形参的任何操作包括重新赋值都应该影响外部变量,然后java中并不会,java传递的不是外部变量,而是拷贝了一份外部变量的地址,而java和c++的值传递的区别在于:

在java方法中对实参对象的属性进行修改是会影响外部变量的,c++不会,原因是c++的值传递拷贝的是整个对象,而java拷贝的是对象的引用

作者举的借钥匙的例子也很恰当,引用传递是直接把钥匙给你,你对钥匙做任何修改(包括换了把别人的钥匙)然后还给你都会影响你原来的钥匙,而值传递就是复刻了一把钥匙给你,你对那把钥匙的任何操作都不会影响原来的钥匙。

另外说一嘴,JavaScript和java在这方面的设计是一样的,山寨一手,妙啊。

hollischuang commented 4 years ago

已经重新整理了值传递的文章