天真,居然还有人认为java的参数传递方式是引用传递

dosomthing(a);

System.out.println("主函数a的值 = "+a);

}

private static void dosomthing(String a) {

a = a+" bug";

System.out.println("修改过后,a = "+a);

}

}

打印结果

修改过后,a = hello bug

主函数a的值 = hello

Process finished with exit code 0

我们发现主函数的a并没有受到dosomthing函数的影响,所以这并不是引用传递,这个时候你说是因为

a = a+" bug";这行代码生成了新的对象,所以才会导致数据不一致,我们先来看看a的赋值情况吧

// class version 52.0 (52)

// access flags 0x21

public class com/ymy/param/StringTypeTest {

// compiled from: StringTypeTest.java

// access flags 0x1

public ()V

L0

LINENUMBER 14 L0

ALOAD 0

INVOKESPECIAL java/lang/Object. ()V

RETURN

L1

LOCALVARIABLE this Lcom/ymy/param/StringTypeTest; L0 L1 0

MAXSTACK = 1

MAXLOCALS = 1

// access flags 0x9

public static main([Ljava/lang/String;)V

// parameter args

L0

LINENUMBER 17 L0

LDC “hello”

ASTORE 1

L1

LINENUMBER 18 L1

ALOAD 1

INVOKESTATIC com/ymy/param/StringTypeTest.dosomthing (Ljava/lang/String;)V

L2

LINENUMBER 19 L2

GETSTATIC java/lang/System.out : Ljava/io/PrintStream;

NEW java/lang/StringBuilder

DUP

INVOKESPECIAL java/lang/StringBuilder. ()V

LDC "\u4e3b\u51fd\u6570a\u7684\u503c = "

INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;

ALOAD 1

INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;

INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String;

INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V

L3

LINENUMBER 21 L3

RETURN

L4

LOCALVARIABLE args [Ljava/lang/String; L0 L4 0

LOCALVARIABLE a Ljava/lang/String; L1 L4 1

MAXSTACK = 3

MAXLOCALS = 2

// access flags 0xA

private static dosomthing(Ljava/lang/String;)V

// parameter a

L0

LINENUMBER 24 L0

NEW java/lang/StringBuilder

DUP

INVOKESPECIAL java/lang/StringBuilder. ()V

ALOAD 0

INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;

LDC " bug"

INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;

INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String;

ASTORE 0

L1

LINENUMBER 25 L1

GETSTATIC java/lang/System.out : Ljava/io/PrintStream;

NEW java/lang/StringBuilder

DUP

INVOKESPECIAL java/lang/StringBuilder. ()V

LDC "\u4fee\u6539\u8fc7\u540e\uff0ca = "

INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;

ALOAD 0

INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;

INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String;

INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V

L2

LINENUMBER 27 L2

RETURN

L3

LOCALVARIABLE a Ljava/lang/String; L0 L3 0

MAXSTACK = 3

MAXLOCALS = 1

}

这是上面代码的字节码代码,我们可以清楚的看到a在赋值的时候都调用了StringBuilder的同String方法,现在我们来看看这个神奇的同String方法。

@Override

public String toString() {

// Create a copy, don’t share the array

return new String(value, 0, count);

}

这是StringBuilder中的toString方法,确实是new了一个新的对象,就算是a变成了一个新的对象,如果是引用传递,主函数的a就不会受影响吗?这点我会讲完对象类型传递之后在进行讲解,请继续往下看。

对象类型传递

=====================================================================

其实上面的两种其实很好区分,很多人都知道是值传递,很多人说java的传递方式是引用传递的原因就是出自这里:传递的参数为对象

有些人看到对象传递的时候会改变主函数的值,就认为java的参数传递是引用传递,有些人又因为基本数据类型不会队主函数的值造成修改,所以他们的结论是:基本数据类型为值传递;对象类型为引用传递,想法很好,那我们现在一起来解开对象传递的神秘面纱,它到底是引用传递还是值传递呢?

go go go !!!!

还是老规矩,我们一起来看一个例子

package com.ymy.param.vo;

/**

  • @ProjectName: demo

  • @Package: com.ymy.param.vo

  • @ClassName: LolVo

  • @Author: 流星007

  • @Description: lol英雄属性

  • csdn:https://blog.csdn.net/qq_33220089

  • 今日头条:https://www.toutiao.com/c/user/5372182357/#mid=1637641735275523

  • @Date: 2020/7/5 15:11

  • @Version: 1.0

*/

public class LolVo {

/**

  • 姓名

*/

private String name;

/**

  • 职业

*/

private String profession;

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public String getProfession() {

return profession;

}

public void setProfession(String profession) {

this.profession = profession;

}

@Override

public String toString() {

return “LolVo{” +

“name='” + name + ‘’’ +

“, profession='” + profession + ‘’’ +

‘}’;

}

}

package com.ymy.param;

import com.ymy.param.vo.LolVo;

/**

  • @ProjectName: demo

  • @Package: com.ymy.param

  • @ClassName: ObjectTypeTest

  • @Author: 流星007

  • @Description: 对象类型传递

  • csdn:https://blog.csdn.net/qq_33220089

  • 今日头条:https://www.toutiao.com/c/user/5372182357/#mid=1637641735275523

  • @Date: 2020/7/5 15:16

  • @Version: 1.0

*/

public class ObjectTypeTest {

public static void main(String[] args) {

LolVo lolVo = new LolVo();

lolVo.setName(“无极剑圣”);

lolVo.setProfession(“刺客”);

dosomthing(lolVo);

System.out.println("主函数 lolVo = "+lolVo);

}

private static void dosomthing(LolVo lolVo) {

lolVo.setProfession(“战士”);

System.out.println("dosomthing lolVo = "+lolVo);

}

}

结果如下:

dosomthing lolVo = LolVo{name=‘无极剑圣’, profession=‘战士’}

主函数 lolVo = LolVo{name=‘无极剑圣’, profession=‘战士’}

Process finished with exit code 0

主函数中剑圣的职业是刺客,在dosomthing中将他修改成,我们发现主函数中剑圣的职业也被修改成战士了,显然这符合引用传递的条件,被调用方修改会影响到调用方也就是主函数,所以这个时候很多人就认为java的对象传递的方式为引用传递,如果你也是这么认为,那么你就要认真看一下我后面的分析。

我们先来一个否定它是引用传递的例子,请看好,不要眨眼

package com.ymy.param;

import com.ymy.param.vo.LolVo;

/**

  • @ProjectName: demo

  • @Package: com.ymy.param

  • @ClassName: ObjectTypeTest

  • @Author: 流星007

  • @Description: 对象类型传递

  • csdn:https://blog.csdn.net/qq_33220089

  • 今日头条:https://www.toutiao.com/c/user/5372182357/#mid=1637641735275523

  • @Date: 2020/7/5 15:16

  • @Version: 1.0

*/

public class ObjectTypeTest {

public static void main(String[] args) {

LolVo lolVo = new LolVo();

lolVo.setName(“无极剑圣”);

lolVo.setProfession(“刺客”);

dosomthing(lolVo);

System.out.println("主函数 lolVo = "+lolVo);

}

private static void dosomthing(LolVo lolVo) {

lolVo = new LolVo();

lolVo.setProfession(“战士”);

System.out.println("dosomthing lolVo = "+lolVo);

}

}

做了小小的改动,仅仅只是在dosomthing方法中加了一行代码:lolVo = new LolVo();

我们再来看运行结果是什么呢?还会和上面一样吗?

dosomthing lolVo = LolVo{name=‘null’, profession=‘战士’}

主函数 lolVo = LolVo{name=‘无极剑圣’, profession=‘刺客’}

Process finished with exit code 0

我们发现主函数中剑圣的属性变回了刺客,并没有受到dosomthing函数的影响,如果是引用传递的话,主函数中剑圣的职业应该是战士而不是刺客。这是为什么呢?为什么是应用传递主函数中剑圣的职业因该是战士呢?

下面我们一起来分析一波

我们假设对象的传递方式为引用传递

在这里插入图片描述

这是堆栈中的信息,当我们将对象lolVo传递给dosomthing的时候,是克隆了一个对象出来还是原来的那个对象呢?我们知道,不管传递的是不是它本身,值都是内存的地址引用,我们现在先假设主函数没有复制,是直接将lolVo传递给了dosomthing,那图形应该是什么样的呢?

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

最后

由于文案过于长,在此就不一一介绍了,这份Java后端架构进阶笔记内容包括:Java集合,JVM、Java并发、微服务、SpringNetty与 RPC 、网络、日志 、Zookeeper 、Kafka 、RabbitMQ 、Hbase 、MongoDB、Cassandra 、Java基础、负载均衡、数据库、一致性算法、Java算法、数据结构、分布式缓存等等知识详解。

image

本知识体系适合于所有Java程序员学习,关于以上目录中的知识点都有详细的讲解及介绍,掌握该知识点的所有内容对你会有一个质的提升,其中也总结了很多面试过程中遇到的题目以及有对应的视频解析总结。

image

image

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
mg.cn/images/e5c14a7895254671a72faed303032d36.jpg" alt=“img” style=“zoom: 33%;” />

最后

由于文案过于长,在此就不一一介绍了,这份Java后端架构进阶笔记内容包括:Java集合,JVM、Java并发、微服务、SpringNetty与 RPC 、网络、日志 、Zookeeper 、Kafka 、RabbitMQ 、Hbase 、MongoDB、Cassandra 、Java基础、负载均衡、数据库、一致性算法、Java算法、数据结构、分布式缓存等等知识详解。

[外链图片转存中…(img-lMNrBzr9-1713629492027)]

本知识体系适合于所有Java程序员学习,关于以上目录中的知识点都有详细的讲解及介绍,掌握该知识点的所有内容对你会有一个质的提升,其中也总结了很多面试过程中遇到的题目以及有对应的视频解析总结。

[外链图片转存中…(img-8LQFMEzP-1713629492027)]

[外链图片转存中…(img-x4UpQInq-1713629492028)]

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

  • 22
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值