Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >java漫谈-Java只有值传递

java漫谈-Java只有值传递

作者头像
WindCoder
发布于 2020-01-24 01:43:06
发布于 2020-01-24 01:43:06
68200
代码可运行
举报
文章被收录于专栏:WindCoderWindCoder
运行总次数:0
代码可运行

《Head First Java》中关于 Java 参数传递的说明:

Java 中所传递的所有东西都是值,但此值是变量所携带的值。引用对象的变量所携带的是远程控制而不是对象本身,若你对方法传入参数,实际上传入的是远程控制的拷贝

《Java编程思想 第四版》中第二章第一节“用引用操作对象”中写到:

尽管一切都看作对象,但操作的标识符实际上是一个对象的引用(reference)。

文中用遥控器(引用)操作电视(对象)为例形象的说明了该引用名词的含义,同时在对定义的“引用”该名词的注释中提到:

有人认为:“很明显,它是一个指针。”但是这种说法是基于底层实现的某种假设。并且,Java中的引用,在语法上更接近C++的引用而不是指针。 还是有很多人不同意用“引用”这个术语。我曾读到的一本书中这样说:“Java所支持的‘按址传递’是完全错误的”,因为Java对象标识符(按那位作者所说)实际上是“对象引用”。并且他接着说任何事物都是“按值传递”的。也许有人会赞成这种精准却让人费解的解释,但我认为我的这种方法可以简化概念上的理解并且不会伤害到任何事物。

对于基本类型(int等)没用争议,肯定是值传递。但String、基本类型的封装类(Integer等)、自定义类(如User等)传递的是一个地址,这就容易让人联想到C++中的指针传递和引用传递。以一个User类为例:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class User {
    private String name;
    private int age;
    private Integer height;

    public User(String name, int age, Integer height) {
        this.name = name;
        this.age = age;
        this.height = height;
    }

    // ......

    // 省略了无参构造函数、所有set/get函数。

    // ......

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", height=" + height+'\'' +
                ", address=" + super.toString() +
                '}';
    }
}

示例1:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class MainDemo {
    public static void main(String[] args) {
        User a = new User("a",10,10);
        User b = new User("b",11, 11);
        PrintUtill.println("交换前:");
        PrintUtill.println("a: "+a);
        PrintUtill.println("b: "+b);
        PrintUtill.printlnRule();
        swap(a,b);
        PrintUtill.println("交换最后:");
        PrintUtill.println("a: "+a);
        PrintUtill.println("b: "+b);
        PrintUtill.printlnRule();
        change(a);
        PrintUtill.println("修改最后:");
        PrintUtill.println("a: "+a);
    }

    public static void swap(Object sa, Object sb){
        Object sc = sa;
        sa = sb;
        sb = sc;
        PrintUtill.println("交换中:");
        PrintUtill.println("sa: " + sa);
        PrintUtill.println("sb: " + sb);
        PrintUtill.printlnRule();
    }


}

结果

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
交换前:
a: User{name='a', age=10, height=10', address=Others.base.common.User@2503dbd3}
b: User{name='b', age=11, height=11', address=Others.base.common.User@4b67cf4d}

--------windcoder.com----------

交换中:
sa: User{name='b', age=11, height=11', address=Others.base.common.User@4b67cf4d}
sb: User{name='a', age=10, height=10', address=Others.base.common.User@2503dbd3}

--------windcoder.com----------

交换最后:
a: User{name='a', age=10, height=10', address=Others.base.common.User@2503dbd3}
b: User{name='b', age=11, height=11', address=Others.base.common.User@4b67cf4d}

--------windcoder.com----------

不管是断点跟踪还是最终打印出的结果,swap方法中确实做了交换(sa和sb的地址做了交换),但并未对方法外有任何影响(a和b的地址指向依旧是原来的未变)。

每个方法的运行都会在Java虚拟机栈中创建一个栈帧,里面存放了局部变量表等内容,方法的运行就是一个栈帧进栈出栈的过程。

如方法swap:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public static void swap(Object sa, Object sb)

此时的sa,sb属于形参,就是形式参数,用于定义方法的时候使用的参数,用来接收调用者传递的参数。形参只有在方法被调用的时候,虚拟机才会分配内存单元,在方法调用结束之后便会释放所分配的内存单元。

相关知识: JVM-Java内存区域 JVM基础小结

换种说法,当调用swap方法时,sa类似C++中的引用,成为地址2503dbd3的一个别名,亦既上面关于《思想》中的引用说的更接近引用而不是指针,不同之处是一旦执行sa = sb;,改变的仅是是sa的指向,对原地址2503dbd3不会造成任何影响。一旦方法执行完,sa被分配到内存单元便会被释放。该实例执行如图:

示例2:

在示例1中追加代码后如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class MainDemo {
    public static void main(String[] args) {
        User a = new User("a",10,10);
        User b = new User("b",11, 11);
        // ......
        // 省略示例1中的代码
        // ......
        change(a);
        PrintUtill.println("修改最后:");
        PrintUtill.println("a: "+a);
    }
    public static void swap(Object sa, Object sb){

        // ...省略

    }
    public static void change(User sa){
        sa.setName("a2");
        sa.setAge(11);
        sa.setHeight(12);
        PrintUtill.println("修改中:");
        PrintUtill.println("sa: " + sa);
    }
}

结果

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// ......
// 省略之前的

交换最后:
a: User{name='a', age=10, height=10', address=Others.base.common.User@2503dbd3}
b: User{name='b', age=11, height=11', address=Others.base.common.User@4b67cf4d}

--------windcoder.com----------

修改中:
sa: User{name='a2', age=11, height=12', address=Others.base.common.User@2503dbd3}
修改最后:
a: User{name='a2', age=11, height=12', address=Others.base.common.User@2503dbd3}

此时函数内发生了变化影响到函数外的数据,change方法外的a和方法的参数sa指向的均是地址2503dbd3,指向未发生变化,但函数中的操作导致所指向的地址2503dbd3中的内容发生了变化,

示例3

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class ListDemo {
    public static void main(String[] args) {
        List<String> list = null;
        // List<String>  list = new ArrayList<String>();
        add(list);
        list.add("3");
        list.add("4");
        PrintUtill.println("list.size:" + list.size());
    }

    public static void add(List<String> list){
        if (list==null){
            list = new ArrayList<String>();
        }
        list.add("1");
        list.add("2");
    }
}

该示例中list最开始为null,意味着没有地址,当作为实参传进add方法中,add.list没有地址,从而执行了list = new ArrayList<String>();,add.list被分配了新的地址,当执行完add方法,add.list就会被释放,但main.list仍旧为空,从而导致NullPointerException(空指针异常)。

扩展

C++中函数参数的几种类型

参考地址

Java 中的参数传递和引用类型

C++ 函数

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
java方法传值还是传递引用(系统的分析一下)
只是把num1,num2的数值拷贝一份交给a,b。a和b做了交换对num1和num2没影响,swap方法结束a和b就销毁了不存在了。这种情况不用多说。
砖业洋__
2023/05/06
2780
面试再问值传递与引用传递,把这篇文章砸给他!
java的值传递和引用传递在面试中一般都会都被涉及到,今天我们就来聊聊这个问题,首先我们必须认识到这个问题一般是相对函数而言的,也就是java中的方法参数,那么我们先来回顾一下在程序设计语言中有关参数传递给方法(或函数)的两个专业术语:
Java技术栈
2018/12/07
4320
多图证明,Java到底是值传递还是引用传递?
开篇先来曝答案,在 Java 语言中,本质只有值传递,而无引用传递,解释和证明详见正文。
Bug开发工程师
2021/01/28
6750
多图证明,Java到底是值传递还是引用传递?
图说Java值传递原理
Java是一门面向对象的程序设计语言,类是其基本抽象单元,而方法是类中可复用的执行单元;当一个Java方法被调用,方法参数的传递方式究竟是基于值传递还是引用传递呢?答案是:值传递 !
程序猿杜小头
2022/12/01
5220
图说Java值传递原理
【IT领域新生必看】深入浅出Java:值传递与引用传递的神奇区别
在Java编程中,方法调用时参数的传递方式是一个重要概念。理解值传递和引用传递的区别,对于编写高效、正确的代码至关重要。对于初学者来说,这两个概念可能会有些混淆,但它们在实际应用中非常重要。本篇文章将详细介绍值传递与引用传递的定义、用法及其区别,帮助你全面理解这些关键概念。
E绵绵
2024/07/08
3110
Java 中的值传递可以分为两种情况分析-Java快速进阶教程
基本数据类型(如 int、float、boolean 等)是存储在栈内存中的,当将它们作为参数传递给方法时,实际传递的是它们的值。例如:
jack.yang
2025/04/05
1060
为什么Java只有值传递
值传递: 调用函数时,将实参复制一份传给函数,函数中修改参数时不会影响实参 引用传递:调用函数时,将实参的地址传给函数,函数中修改参数会影响实参。 判断是值传递还是引用传递的标准,和传递参数的类型是没有关系的。
Qwe7
2022/04/01
5240
Java到底是引用传递还是值传递?
首先回顾一下在程序设计语言中有关将参数传递给方法(或函数)的一些专业术语。 按值调用(call by value)表示方法接收的是调用者提供的值,而按引用调用(call by reference)表示方法接收的是调用者提供的变量地址。一个方法可以修改传递引用所对应的变量值,而不能修改传递值调用所对应的变量值。它用来描述各种程序设计语言(不只是 Java)中方法参数传递方式。
黑洞代码
2021/01/14
8600
Java到底是引用传递还是值传递?
为什么大家都说Java中只有值传递?
最近跟Java中的值传递和引用传递杠上了,一度怀疑人生。查了很多资料,加上自己的理解,终于搞清楚了,什么是值传递和引用传递。也搞明白了,为什么大家都说Java只有值传递,没有引用传递。原来,我一直以来的认知都是错误的。。。
烟雨星空
2020/06/16
1.7K0
这一次,让你彻底理解Java的值传递和引用传递!
学过Java基础的人都知道:值传递和引用传递是初次接触Java时的一个难点,有时候记得了语法却记不得怎么实际运用,有时候会的了运用却解释不出原理,而且坊间讨论的话题又是充满争议:有的论坛帖子说Java只有值传递,有的博客说两者皆有;这让人有点摸不着头脑,下面我们就这个话题做一些探讨,对书籍、对论坛博客的说法,做一次考证,以得出信得过的答案。
Java团长
2019/06/26
1K0
这一次,让你彻底理解Java的值传递和引用传递!
Java漫谈-深拷贝与浅拷贝
2、运用反射手段创建对象,调用java.lang.Class 或者 java.lang.reflect.Constructor 类的newInstance()实例方
WindCoder
2018/09/19
3.2K0
说说Java到底是值传递还是引用传递
首先,我们必须要搞清楚,到底什么是值传递,什么是引用传递,否则,讨论 Java 到底是值传递还是引用传递就显得毫无意义。
沉默王二
2020/04/23
5030
说说Java到底是值传递还是引用传递
java怎么区分值传递和引用传递
java中值传递和引用传递一直饱受争议难以区分,下面我通过几个例子来区分一下什么时间是值传递,什么时间是引用传递
用户5166556
2019/04/16
7710
如何理解 Java的值传递和引用传递
HaC haC = new HaC(); 和 changeName(HaC haC)参数里面的两个haC 地址都是一样的,指向同一个对象。
曾高飞
2025/06/16
1090
Java真的只有值传递?
值传递(pass by value)是指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。
一觉睡到小时候
2019/07/02
7430
Java真的只有值传递?
Java 基础概念·Java 只有值传递
当我们调用一个有参函数的时候,会把实际参数传递给形式参数。在程序语言中,这个传递过程中有两种情况,即值传递和引用传递。
数媒派
2022/12/01
4650
Java的JVM介绍以及java的值传递和引用传递
面试的时候碰到的了一个java基础问题,竟然给问蒙了,回来之后感觉针对这个问题总结一下
包子388321
2020/06/16
1.1K0
java中值传递和引用传递
public static void main(String[] args) {int a=1;change(a);System.out.println("交换a后的值:" a);}
chenchenchen
2019/11/05
9280
Java值传递与引用传递
Java面试题: 当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递?   答案基本上是:值传递 说明:得出这种结论的前提必须是
阳光岛主
2019/02/19
1.3K0
Java中真的只有值传递么?
关于这个问题应该是存在争议的。根据测试出来的结果和我们自己的经验,以及口口相传或是上学时老师讲的,我们认为是第一种。但第二种说法的呼声也很高,渐渐地我们也认为第2中才是对的。那么下面我们就来分析一下这个问题。
编程大道
2020/02/11
1.3K0
相关推荐
java方法传值还是传递引用(系统的分析一下)
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档