
本文共 2822 字,大约阅读时间需要 9 分钟。
Java参数传递机制:by value Or by reference?
一、前言
春招在即,相信很多小伙伴像我一样奔波于毕业与就业之间,但是学习不可少噢。今天抽点时间和大家聊聊 Java开发岗中,面试官常问或者笔试中常考的Java传参机制。
很多时候人们会因为[ Java 操控的是object reference(对象引用,虽然网上很多文章说是对象,这里不反驳)] 而臆测[ Java传参数也是以by reference (地址)方式进行传递]。因此,如果不能很准确地理解其中奥妙,很多时候在面试或者笔试的时候,则可能造成不必要的错误。(郑重声明:Java 传参只有 by value 方式)
举个栗子噢!!
import java.awt.Point;public class PassByValue {
public static void modifyPoint(Point pt,int i) {
pt.setLocation(10, 10);
i = 10;
System.out.println("During modifPoint "+"pt = "+pt+"and i = "+i); }
public static void main(String[] args) {
Point p = new Point(1,1);
int i = 1;
System.out.println("Before modifPoint "+"pt = "+p+"and i = "+i);
modifyPoint(p, i);
System.out.println("During modifPoint "+"pt = "+p+"and i = "+i); }}
说明:该段代码先是建立一个 Point 对象并设其初值为(1,1),然后将其赋值给Object reference 变量 p,同时对基本数据类型 int i 赋予数值 1。之后调用 static modifyPoint() 方法,并传入 p 和 i。modifyPoint() 方法中对参数 pt 调用 setLocation() ,将其坐标改为(10,10)。同时将参数i也赋值为10,最后返回并打印 p 和 i 的值。
大家思考一下,看看这段代码的输出为何?
程序输入如下:
很明显,modifyPoint()方法改变了创建的Point对象,那为什么没有改变基本数据类型 int i 的值呢?保持思考,一起来探讨一下吧!!!
二、by value
其实Java传参方式是以 (by value)传值 OR (by reference)传引用 一直都在Java里有较大的争论,那么先来认识一下Java中的传值吧。
来,举个栗子 !!
public class PassByValue {
public static void swap(int a,int b) {
int temp = a;
a = b ;
b = temp; }
public static void main(String[] args) {
int a = 10;
int b = 100;
System.out.println("a 和 b 交换前:a="+a+" b="+b);
swap(a, b);
System.out.println("a 和 b 交换后:a="+a+" b="+b); }}
说明:创建两个基本数据类型 int a=10;int b=100,并调用swap()方法交换两个变量的值,然后分别输出调用方法前后a和b的值。程序输入如下:
为什么这里 a 和 b 没有交换数据值呢?要深入了解这个原因,那我们来看看这个过程中a和b都发生了什么。
(调用swap()方法,创建a,b变量副本)
(执行完成swap()方法)
因此,无论是 modifyPoint() 方法中的变量 int i ,还是 swap() 方法中的int a;int b 都是通过by value 方式传递,所以它们都是收到了对应变量的一个副本,然后对应方法把变量的副本对应的数据值改变了,但是不会影响变量本身的数据值,所以输出还是变量本身。
三、by reference
拿第一个栗子举例来说,看完by value的数据变化过程以及我们一直强调Java只有by value方式传参,那么岂不是所有改变数据的方法都是无法达到目标? 为什么modifyPoint()为什么把Point对象变量数据值改变了呢?
这里就不得不说,对象的存储了。我们都知道基本数据类型变量或者常量一般都存储在本地方法栈中,能很快的获取到变量,但是由于对象所具有的数据量较多,而本地方法栈较小,无法存储较多的对象。因此,聪明的工程师们想到了堆,使用堆来存储对象本身,而使用方法栈来存储对对象的引用(地址),使得我们可以很快的找到对象的同时又不会造成对栈内存的消耗。
因此,我们平日里创建的 new Object(),获得是对象引用,而不是对象本身。举个栗子吧!!!
User user = new User();
user 便是对象 User 的引用,而不是对象本身,很多文章都在说是对象,我们可以“认为”是对象,但是必须知道是对象的引用,而不是对象本身。
扯远了…
事实上在 modifyPoint() 方法中,是在与[ Point 对象的 reference 的副本 ]打交道,而不是与 [ Point 对象的副本 ]打交道。因此(继续拿第一个栗子来说)p 是个 object reference ,并且 Java 以 by value 方式传递参数。更明确地说,此时Java以by value 方法传递 object reference 。
当p从main()被传入modifyPoint()时,传递的是p(也就是一个reference)的副本。所以modifyPoint()是在与同一个对象打交道,只不过通过别名pt罢了。在进入modifyPoint()之后和执行之前,这个对象都如下:
(执行modifyPoint()方法前)
(modifyPoint()通过pt改变Point对象)
因此,我们可以通过使用“by reference”方式进行传值方式,达到修改数据的方式。如果还有人说Java有引用传参方式,那么请把这篇文章甩给它。
那么如果我们希望一个引用类型的数据传参后数据不被改变,我们该怎么办呢?这里以为modifyPoint()为例子进行说明!
- 对modifyPoint()传递一个Point对象的克隆件(Clone)
- 令Point对象为immutable(不可改变的)
这里给出两种解决方案,大家可以自己去学习并验证。学习就是体会,自己学到的才是自己的噢。
转载地址:https://blog.csdn.net/weixin_43452424/article/details/115187138 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!
发表评论
最新留言
关于作者
