首页 星云 工具 资源 星选 资讯 热门工具
:

PDF转图片 完全免费 小红书视频下载 无水印 抖音视频下载 无水印 数字星空

Java是值传递还是引用传递,又是怎么体现的

编程知识
2024年09月07日 15:58

关于Java是值传递还是引用传递,可以从代码层面来实现一下拿到结果
执行下面的代码:

    public static void main(String[] args) {
        int num = 10;
        String name = "Tom";
        modify(num, name);
        System.out.println("第3次打印int:" + num);
        System.out.println("第3次打印String:" + name);
        System.out.println("------------------------------------");
    }

    public static void modify(int n, String str){
        System.out.println("第1次打印int:" + n);
        System.out.println("第1次打印String:" + str);
        System.out.println("------------------------------------");

        // 尝试在方法内部修改传进来的参数
        n = 999;
        str = "ABC";
        System.out.println("第2次打印int:" + n);
        System.out.println("第2次打印String:" + str);
        System.out.println("------------------------------------");
    }

打印出来的结果如下:

第1次打印int:10
第1次打印String:Tom
------------------------------------
第2次打印int:999
第2次打印String:ABC
------------------------------------
第3次打印int:10
第3次打印String:Tom
------------------------------------

可以看到无论是基本类型还是引用类型,传参数进去的时候的值和执行完modify方法后的值是一样的,也就是第1次打印和第三次打印是一样的。可是为什么明明在第2次已经修改成功了,第3次却又变回去了呢?
尝试换个方法把参数拿出来,

    public static void main(String[] args) {
        int num = 10;
        String name = "Tom";
        int modifiedNum = modifyAndReturn(num);
        String modifiedName = modifyAndReturn(name);
        System.out.println("打印num:" + num);
        System.out.println("打印name:" + name);
        System.out.println("------------------------------------");
        System.out.println("打印modifiedNum:" + modifiedNum);
        System.out.println("打印modifiedName:" + modifiedName);
    }

    public static int modifyAndReturn(int n){
        System.out.println("modifyAndReturn第1次打印int:" + n);

        // 尝试在方法内部修改传进来的参数
        n = 999;
        System.out.println("modifyAndReturn第2次打印int:" + n);
        System.out.println("------------------------------------");
        return n;
    }

    public static String modifyAndReturn(String str){
        System.out.println("modifyAndReturn第1次打印String:" + str);

        // 尝试在方法内部修改传进来的参数
        str = "ABC";
        System.out.println("modifyAndReturn第2次打印String:" + str);
        System.out.println("------------------------------------");
        return str;
    }

得到的结果为

modifyAndReturn第1次打印int:10
modifyAndReturn第2次打印int:999
------------------------------------
modifyAndReturn第1次打印String:Tom
modifyAndReturn第2次打印String:ABC
------------------------------------
打印num:10
打印name:Tom
------------------------------------
打印modifiedNum:999
打印modifiedName:ABC

可以看到通过return出来的值,的确是被改变了的,那又是为什么导致这个改变没有应用到参数本体呢?修改下代码再次测试

public static void main(String[] args) {
        int num = 10;
        String name = "Tom";
        // 打印num和str的地址
        System.out.println("修改前,传参前:");
        System.out.println(System.identityHashCode(num));
        System.out.println(System.identityHashCode(name));

        System.out.println("---------------------------");
        printAddr(num, name);

        System.out.println("---------------------------");
        System.out.println("修改后,执行完方法后:");
        System.out.println(System.identityHashCode(num));
        System.out.println(System.identityHashCode(name));
    }

    public static void printAddr(int n, String str){
        // 打印n和str的地址
        System.out.println("修改前,传参后:");
        System.out.println(System.identityHashCode(n));
        System.out.println(System.identityHashCode(str));

        n = 999;
        str = "ABC";

        // 打印n和str的地址
        System.out.println("---------------------------");
        System.out.println("修改后,传参后:");
        System.out.println(System.identityHashCode(n));
        System.out.println(System.identityHashCode(str));
    }

执行结果如下

修改前,传参前:
1324119927
990368553
---------------------------
修改前,传参后:
1324119927
990368553
---------------------------
修改后,传参后:
1096979270
1078694789
---------------------------
修改后,执行完方法后:
1324119927
990368553

可以看到传参进来的参数地址是和外部定义的地址是同一个,但是修改之后会指向另一个新的地址,导致原来地址上的数据不会受到影响,这其实是一个保护机制,防止参数传入方法内被篡改指向。

下面演示引用类型的另一种情况,一些老铁可能以为是对引用类型本身的修改,其实这是不对的。
先定义一个类Person

class Person{
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

	@Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }	
}

执行下面的代码,可以看到传进去的参数的属性被改变


    public static void main(String[] args) {
        Person person = new Person("Rosy", 24);
        String [] strings = {"AAA", "BBB", "CCC"};
        System.out.println("第1次打印:");
        System.out.println(person);
        System.out.println(Arrays.toString(strings));

        modifyObjAndPrintValue(person, strings);

        System.out.println("---------------------------");
        System.out.println("第4次打印:");
        System.out.println(person);
        System.out.println(Arrays.toString(strings));
    }

    public static void main5(String[] args) {
        Person person = new Person("Rosy", 24);
        String [] strings = {"AAA", "BBB", "CCC"};
        System.out.println("第1次打印:");
        System.out.println(System.identityHashCode(person));
        System.out.println(System.identityHashCode(person.getAge()));
        System.out.println(System.identityHashCode(person.getName()));
        System.out.println(System.identityHashCode(strings));

        modifyObj(person, strings);

        System.out.println("---------------------------");
        System.out.println("第4次打印:");
        System.out.println(System.identityHashCode(person));
        System.out.println(System.identityHashCode(person.getAge()));
        System.out.println(System.identityHashCode(person.getName()));
        System.out.println(System.identityHashCode(strings));
    }

    public static void modifyObjAndPrintValue(Person person, String [] strings){
        System.out.println("---------------------------");
        System.out.println("第2次打印:");
        System.out.println(person);
        System.out.println(Arrays.toString(strings));

        person.setAge(1024);
        person.setName("ABC");
        strings[0] = "XXX";

        System.out.println("---------------------------");
        System.out.println("第3次打印:");
        System.out.println(person);
        System.out.println(Arrays.toString(strings));
    }

执行结果为

第1次打印:
Person{name='Rosy', age=24}
[AAA, BBB, CCC]
---------------------------
第2次打印:
Person{name='Rosy', age=24}
[AAA, BBB, CCC]
---------------------------
第3次打印:
Person{name='ABC', age=1024}
[XXX, BBB, CCC]
---------------------------
第4次打印:
Person{name='ABC', age=1024}
[XXX, BBB, CCC]

从结果可以发现,Person对象的属性都被修改,String数组的元素也被修改,说明参数里对属性或数组的修改是会影响对象本身的,具体可以打印地址再查看一下:


    public static void main(String[] args) {
        Person person = new Person("Rosy", 24);
        String [] strings = {"AAA", "BBB", "CCC"};
        System.out.println("第1次打印:");
        System.out.println(System.identityHashCode(person));
        System.out.println(System.identityHashCode(person.getAge()));
        System.out.println(System.identityHashCode(person.getName()));
        System.out.println(System.identityHashCode(strings));
        System.out.println(System.identityHashCode(strings[0]));

        modifyObjAndPrintAddr(person, strings);

        System.out.println("---------------------------");
        System.out.println("第4次打印:");
        System.out.println(System.identityHashCode(person));
        System.out.println(System.identityHashCode(person.getAge()));
        System.out.println(System.identityHashCode(person.getName()));
        System.out.println(System.identityHashCode(strings));
        System.out.println(System.identityHashCode(strings[0]));
    }


    public static void modifyObjAndPrintAddr(Person person, String [] strings){
        System.out.println("---------------------------");
        System.out.println("第2次打印:");
        System.out.println(System.identityHashCode(person));
        System.out.println(System.identityHashCode(person.getAge()));
        System.out.println(System.identityHashCode(person.getName()));
        System.out.println(System.identityHashCode(strings));
        System.out.println(System.identityHashCode(strings[0]));

        person.setAge(1024);
        person.setName("ABC");
        strings[0] = "XXX";

        System.out.println("---------------------------");
        System.out.println("第3次打印:");
        System.out.println(System.identityHashCode(person));
        System.out.println(System.identityHashCode(person.getAge()));
        System.out.println(System.identityHashCode(person.getName()));
        System.out.println(System.identityHashCode(strings));
        System.out.println(System.identityHashCode(strings[0]));
    }
第1次打印:
990368553
1096979270
1078694789
1831932724
1747585824
---------------------------
第2次打印:
990368553
1096979270
1078694789
1831932724
1747585824
---------------------------
第3次打印:
990368553
1023892928
558638686
1831932724
1149319664
---------------------------
第4次打印:
990368553
2093631819
558638686
1831932724
1149319664

从地址上可以看到,person和strings的地址一直没有变过。而在参数内部修改的person属性和数组元素,会对这部分成员的地址进行修改,并且会应用到对象本体上。

总结下来就是,无论传的是基本类型还是引用类型,只要在方法内部尝试改变参数地址的,都只能在方法内部使用,不会影响本体,而在方法内部改变属性的,会把对应的改变应用到本体上。所以Java是值传递的,传参的时候并不是把本身传入,而是创建一个副本,当被修改指向的时候不会影响本身,修改属性由于不会修改本身的地址,因此的时候可以应用到本体上。

From:https://www.cnblogs.com/huajieyu/p/18401887
本文地址: http://shuzixingkong.net/article/1811
0评论
提交 加载更多评论
其他文章 跳跃表
概述 跳跃表(SkipList)是链表加多级索引组成的数据结构。链表的数据结构的查询复条度是 O(N)。为了提高查询效率,可以在链表上加多级索引来实现快速查询。跳跃表不仅能提高搜索性能。也能提高插入和删除操作的性能。索引的层数也叫作跳跃表的高度 查找 在跳跃表的结构中会首先从顶层开始查找,当顶层不存
跳跃表 跳跃表 跳跃表
设计模式之模板方法模式(三分钟学会一个设计模式)
模板方法模式(Template Method Pattern)也称之为模板模式(Template Pattern),是设计模式中最简单的模式之一。 先来看定义:定义一个操作中算法的骨架(模板),将一些步骤延迟到子类中,模板方法使得子类可以不改变算法的结构即可重新定义算法某些特定的步骤。这个定义还是有
设计模式之模板方法模式(三分钟学会一个设计模式) 设计模式之模板方法模式(三分钟学会一个设计模式)
事务发件箱模式在 .NET 云原生开发中的应用(基于Aspire)
原文:Transactional Outbox in .NET Cloud Native Development via Aspire 作者:Oleksii Nikiforov 总览 这篇文章提供了使用 Aspire、DotNetCore.CAP、Azure Service Bus、Azure SQ
事务发件箱模式在 .NET 云原生开发中的应用(基于Aspire) 事务发件箱模式在 .NET 云原生开发中的应用(基于Aspire) 事务发件箱模式在 .NET 云原生开发中的应用(基于Aspire)
HashMap深入讲解
HashMap是Java中最常用的集合类框架,也是Java语言中非常典型的数据结构, 而HashSet和HashMap者在Java里有着相同的实现,前者仅仅是对后者做了一层包装,也就是说HashSet里面有一个HashMap(适配器模式)。因此了解HashMap源码也就了解HashSet了 介绍 K
HashMap深入讲解
五子棋AI:实现逻辑与相关背景探讨(下)
前文回顾 在上篇文章中,我们约定了一种衡量格子价值的方式,如下表。 综合价值排序 己方价值 敌方价值 对应的奖励数值 1 Lv1 ? \(2^{20}\) 2 ? Lv1 \(2^{16}\) 3 Lv2 ? \(2^{12}\) 4 ? Lv2 \(2^{8}\) 5 Lv3 ? \(2^{4}\
使用 `Roslyn` 分析器和修复器对.cs源代码添加头部注释
之前写过两篇关于Roslyn源生成器生成源代码的用例,今天使用Roslyn的代码修复器CodeFixProvider实现一个cs文件头部注释的功能, 代码修复器会同时涉及到CodeFixProvider和DiagnosticAnalyzer, 实现FileHeaderAnalyzer 首先我们知道修
使用 `Roslyn` 分析器和修复器对.cs源代码添加头部注释 使用 `Roslyn` 分析器和修复器对.cs源代码添加头部注释 使用 `Roslyn` 分析器和修复器对.cs源代码添加头部注释
线性dp:LeetCode516 .最长回文子序列
LeetCode516 .最长回文子序列 题目叙述: 力扣题目链接(opens new window) 给你一个字符串 s ,找出其中最长的回文子序列,并返回该序列的长度。 子序列定义为:不改变剩余字符顺序的情况下,删除某些字符或者不删除任何字符形成的一个序列。 示例 1: 输入:s = &quot
线性dp:LeetCode516 .最长回文子序列 线性dp:LeetCode516 .最长回文子序列 线性dp:LeetCode516 .最长回文子序列
XGBoost模型 0基础小白也能懂(附代码)
XGBoost 是 eXtreme Gradient Boosting 的缩写称呼,它是一个非常强大的 Boosting 算法工具包,优秀的性能(效果与速度)让其在很长一段时间内霸屏数据科学比赛解决方案榜首,现在很多大厂的机器学习方案依旧会首选这个模型。
XGBoost模型 0基础小白也能懂(附代码) XGBoost模型 0基础小白也能懂(附代码) XGBoost模型 0基础小白也能懂(附代码)