天天看点

【一看就懂】为什么说Java没有引用传递 !前言值传递和引用传递的区别有必要搞清楚什么是引用传递引用传递和传递引用的区别为什么Java传引用对象是值传递,形参改变会影响到实参?如何证明Java中传递引用是“值传递”,而不是“引用传递”?

文章目录

  • 前言
  • 值传递和引用传递的区别
  • 有必要搞清楚什么是引用传递
  • 引用传递和传递引用的区别
  • 为什么Java传引用对象是值传递,形参改变会影响到实参?
    • (1)先说一般的引用对象
    • (2)再说String
  • 如何证明Java中传递引用是“值传递”,而不是“引用传递”?

前言

本文想说清的问题有两个:

1.引用传递并不是传递引用

2.Java没有引用传递!只有值传递!

  • 在【Java编程思想】一书中的第二章的最下方有这么一行小字,记录着作者认同Java只有值传递的观点;以及提到了“引用”一词,只是为了贴近C++的程序员,了解Java对象的操作的一个概念。
    【一看就懂】为什么说Java没有引用传递 !前言值传递和引用传递的区别有必要搞清楚什么是引用传递引用传递和传递引用的区别为什么Java传引用对象是值传递,形参改变会影响到实参?如何证明Java中传递引用是“值传递”,而不是“引用传递”?
  • 本文想表达的是,并不是使用引用操纵对象,或者传递(拷贝)了引用地址,就是引用传递了,依旧是值拷贝,是值传递!

值传递和引用传递的区别

  • Java值传递就是当前方法调用新的方法的时候,入栈了一个新的栈帧对应被调用的方法,然后将实参进行值拷贝,拷贝到新栈帧中的局部变量表进行存储(注意拷贝的可以是基本类型的值,也可以是引用类型的引用地址)
  • 什么是引用传递? 引用传递绝对不是传递地址这么简单!!不要被大学C语言老师给骗了!,因为Java中没有引用传递,因此用C++来举例。
  • 引用传递,实参通过引用传递,传递给形参的时候,形参其实相当于实参的一个别名,形参没有自己的存储数据的内存地址,可以说他就是实参的一个替身。
  • 当对形参操作的时候,其实就相当于对实参进行了操作!实参是会受到影响的!

有必要搞清楚什么是引用传递

引用传递绝对不是传递地址这么简单!

从C++来看,使用引用传递时,形参其实就是实参的一个别名,其实实参和形参是同一个变量。

  • 引用变量是变量的另一个别名,它没有自己的存储数据的内存位置,它访问的是另一个变量的内存位置。
  • 对引用变量作出的任何更改,实际上都是对它所引用的变量内存位置中存储数据的更改。
  • 当使用引用变量作为形参时,它将变为实参列表中相应变量的别名,对形参进行的任何更改都将真正更改正在调用它的函数中的变量。当以这种方式将数据传递给形参时,该实参被称为按引用传递。

引用传递和传递引用的区别

  • 话先说明白:传递引用其实是值传递,只不过复制的是对象的引用地址罢了。
  • 值传递,单纯的值拷贝,非常的纯粹。(有些人会有疑惑:“为什么传递引用对象的时候,形参发生改变,会造成实参改变,这也算值传递?”,下面会说清楚这件事!)·
  • 引用传递的话:形参就是实参的一个别名罢了,两个参数其实就只有实参一个变量 ,形参的操作时会直接影响实参的。

为什么Java传引用对象是值传递,形参改变会影响到实参?

(1)先说一般的引用对象

  • 首先要知道对象实体是在堆中创建的,栈中的变量保存的是对象的引用地址(不给对象重写toString()方法的时候输出对象,打印出来的信息可以看到。)
  • Java中传递引用对象,是将引用变量中存的对象的引用地址进行值拷贝!。也就是从一个栈帧,复制到其调用的栈帧中的局部变量表的形参下进行存储!
  • 这个时候两个引用变量存的是同一个堆中对象的引用地址(注意是堆中的同一个唯一的对象!),这个时候形参对其进行修改,那么实参指向的也是这个唯一的对象,当然能够感知到形参对其进行修改了。
  • 但是这确实是值拷贝!因为实参的引用地址原封不动的拷贝到了形参下进行存储!只不过形参改变了这个地址指向的值被实参感知到了。这可不影响值传递的原则定义。

(2)再说String

  • 那么为什么传String对象也是传递引用,形参修改了,实参不会影响???
  • 因为String是final修饰的!
  • 比如形参X存储的是"hello"字符串的地址aaaaa,并将地址传递给了形参Y,那么Y中一开始存储的的确是aaaaa这个地址。
  • 只不过,如果Y对值进行修改,Java会在堆中的字符串常量池中,将另外的地址赋值给Y。但是原先的"hello"的地址是不会改变的!X依旧指向他!只不过Y因为修改了值,存储了一个新的引用地址bbbbb。
  • 这个时候Y对值的修改,当然是不会影响到X存储的引用地址啦!因为是值拷贝嘛!

如何证明Java中传递引用是“值传递”,而不是“引用传递”?

先在心中默念几遍,如果是引用传递,形参就是实参,只不过形参取了个别名罢了,形参实参是一个东西!
  • 好的现在我们开始试验:
  • Step 1.假设这里有一个再简单不过的Student对象(其中有构造函数getter和setter以及toString()方法):
    【一看就懂】为什么说Java没有引用传递 !前言值传递和引用传递的区别有必要搞清楚什么是引用传递引用传递和传递引用的区别为什么Java传引用对象是值传递,形参改变会影响到实参?如何证明Java中传递引用是“值传递”,而不是“引用传递”?
  • Step 2.下面这段代码证明了Java中的传递引用不是引用传递
    【一看就懂】为什么说Java没有引用传递 !前言值传递和引用传递的区别有必要搞清楚什么是引用传递引用传递和传递引用的区别为什么Java传引用对象是值传递,形参改变会影响到实参?如何证明Java中传递引用是“值传递”,而不是“引用传递”?
    我们看看输出:
    【一看就懂】为什么说Java没有引用传递 !前言值传递和引用传递的区别有必要搞清楚什么是引用传递引用传递和传递引用的区别为什么Java传引用对象是值传递,形参改变会影响到实参?如何证明Java中传递引用是“值传递”,而不是“引用传递”?
解释一下:
  • 因为如果是引用传递的话,形参就是实参,只不过取了个别名,俩玩意儿是同一东西,那么在change方法中new一个新的Student对象,并存在形参中,这个操作会改变实参中存储的值也变成新new的对象的引用地址!
  • 然后实际上我们发现并非如此!实参保存的引用地址指向的对象还是原先的对象并没有发生改变!
  • 跟String引用对象传参是一样的道理!实参指向的是一个aaaaa的引用地址,传给了形参,可是形参new了个新的对象,并将新对象的引用地址bbbbb存到了形参中。这并不会影响到实参中存储的aaaaa地址,因为Java中只有值传递,是最纯粹的值拷贝!不是别名不是分身!

【我尽量用最直白的话来讲述出我对这个问题的理解;有哪里讲错了可以提出,我们共同进步】

————— END —————