深入分析java传参
概述
java中的参数传递问题可以根据参数的类型大致可以分为三类:传递基本类型,传递String类型,传递引用类型,至于最终是否可以归纳为值传递和引用传递,根据每个人的理解不同,答案不同,此处不做强调。
传递基本类型
public class Test1 {
public static void main(String[] args) {
int n = 3;
System.out.println("Before change, n = " + n);
changeData(n);
System.out.println("After changeData(n), n = " + n);
}
public static void changeData(int n) {
n = 10;
}
}
结果:Before change, n = 3
After changeData(n), n = 3
解析(比较简单不结合字节码分析):
1.线程调用main方法,创建栈帧A,局部变量表有n=3
2.main方法中调用changeDate方法,传入参数n=3,线程创建栈帧B,将10赋给n后,局部变量表有n=10
3.changeDate方法执行完毕,栈帧B弹出,输出栈帧A中n的值为3
传递String类型
public class Test2 {
public static void main(String[] args) {
String str = new String("String");
System.out.println("Before change, str = " + str);
changeData(str);
System.out.println("After changeData(n), str = " + str);
}
public static void changeData(String str) {
str = "newString";
}
}
结果:Before change, str = String
After changeData(n), str = String
指令码为(将上述代码两条输出语句删除后进行编译,反汇编,为了突出主要过程):
public static void main(java.lang.String[]);
0: new #2 // class java/lang/String
3: dup
4: ldc #3 // 返回常量池中字符串的引用,并且入栈
6: invokespecial #4 // Method java/lang/String."<init>":(Ljava/lang/String;)V
9: astore_1
10: aload_1
11: invokestatic #5 // Method changeData:(Ljava/lang/String;)V
14: return
public static void changeData(java.lang.String);
0: ldc #6 // 返回常量池中字符串的引用,并且入栈
2: astore_0
3: return
}
解析: 1.new,dup,Idc,invokespecial,astore_1:在栈帧A中完成了实例化一个String对象,并将一个指向该对象的引用存入了局部变量表的操作
2.aload_1,invokestatic:调用changeDate方法,传入引用,创建栈帧B
3.Idc,astore_0,return:在栈帧B中完成了将指向常量池中"newString"字符串的引用压入操作数栈并且将该引用存入局部变量表的操作,之后栈帧B弹出
4.栈帧A局部变量表中那个引用依然指向String对象,其值依然为String
传递引用类型
public class Test3 {
public static void main(String[] args) {
StringBuffer sb = new StringBuffer("Hello ");
System.out.println("Before change, sb = " + sb);
changeData(sb);
System.out.println("After changeData(n), sb = " + sb);
}
public static void changeData(StringBuffer strBuf) {
strBuf.append("World!");
}
}
结果:Before change, sb = Hello
After changeData(n), sb = Hello World!
指令码为(将上述代码两条输出语句删除后进行编译,反汇编,为了突出主要过程):
public static void main(java.lang.String[]);
0: new #2 // class java/lang/StringBuffer
3: dup
4: ldc #3 // String Hello
6: invokespecial #4 // Method java/lang/StringBuffer."<init>":(Ljava/lang/String;)V
9: astore_1
10: aload_1
11: invokestatic #5 // Method changeData:(Ljava/lang/StringBuffer;)V
14: return
public static void changeData(java.lang.StringBuffer);
stack=2, locals=1, args_size=1
0: aload_0
1: ldc #6 // String World!
3: invokevirtual #7 // Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/ StringBuffer;
6: pop
7: return
}
解析(说明下和String传参区别的地方):
在changeDate方法中有了aload操作,也就是将传递来的引用压入了操作数栈,并且之后的Idc,invokevirtual操作说明对该引用指向的对象进行了相关操作,很显然在栈帧B弹出时,栈帧A局部变量表中的引用指向的对象发生了变化。
总结
回头看一下:综合来看基本变量和String变量传参,对传入参数进行改变的时候,都没有用到传入的参数值(也就是没有aload操作),直接将基本类型值或者常量池中字面量引用赋值给变量。怎么看都有些别扭,因为String本质上是一个类和基本类型中终究是不同的,我的理解是:String类既然设计成final类,暗示string变量的复用带来的正面效果大于由于不能改变String变量而必须存入一个新的string字符串的负面效果,那么为了复用,对于String变量的赋值语句在编译时便进行了特殊处理,在常量池中找是否已经存在该字符串,如果有,返回引用,达到复用的目的,如果没有,将字符串放入常量池返回该引用为了下次复用。而对于其他引用变量传参,当栈帧B要对传入参数进行改变的时候,都会进行aload操作,由于jvm是基于栈的字节码执行,aload的参数只能是栈帧A中引用的复制,这点区别于C,由于C是基于寄存器的操作,其指针传递,操作是的是指针变量本身,可以用一个经典的引用交换实例区分,网上有举例,不在累述,以上。
深入分析java传参的更多相关文章
- Java传参那些事!
刚刚学习java传参的时候很纠结,也非常的不理解!课本上的“按值传递”和“按址传递”搞的自己是一头雾水,后来写的项目多了,自然就明白了! 现在写传参几乎就是条件反射一般——“秒成”,分享当初自己为此写 ...
- Java传参都是传引用变量的副本
最近做练习时碰到一个问题,Java到底是怎样传参的,经过查资料与实验,我发现Java传参都是传引用变量的副本值. 1 Java中的引用变量 1.1 字面值引用变量:即基本数据类型的引用变量 ,如 in ...
- java 传参方式--值传递还是引用传递
java 传参方式--值传递还是引用传递 参数是按值而不是按引用传递的说明 Java 应用程序有且仅有的一种参数传递机制,即按值传递.写它是为了揭穿普遍存在的一种神话,即认为 Java 应用程序按引用 ...
- 使用java传参调用exe并且获取程序进度和返回结果的一种方法
文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/ 1.背景 在某个项目中需要考虑使用java后台调用由C#编写的切图程序( ...
- Java传参-基本数据类型和引用数据类型作为参数的区别(值传递)
java中的方法可以传递参数,参数的传递方法就是值传递. 参数有形参和实参,定义方法时写的参数叫形参,真正调用方法时,传递的参数叫实参. 调用方法时,会把实参传递给形参,方法内部其实是在使用形参. 所 ...
- String的按值传递,java传参都是传值
java中对象作为参数传递给一个方法,到底是值传递,还是引用传递? String和int参数传递是按值传递还是引用传递? 一道面试题目,String的传递: public String change( ...
- Java传参
1. 如果参数是基本数据类型(int.long等),传值.方法内部改变参数值,外部值不变. 2. 如果参数是对象类型,传地址.方法内部改变对象值,外部对象值改变.但是,如果方法内部调用new重新构 ...
- java传参问题
参考链接:https://www.cnblogs.com/linkstar/p/5951141.html public class Example { String testString = publ ...
- Java传参:值传递 or 引用传递 ?
刚开始学Java的时候一度以为:基本数据类型是值传递,引用类型是引用传递.新人很容易在这两个概念上面被搞糊涂,后来看了Hollis的文章才明白了Java中只有值传递. 接下来我能用简单明了的方式来说明 ...
随机推荐
- 使用Python实现贪心算法
题目: 圣诞节来临了,在城市A中,圣诞老人准备分发糖果.现在有多箱不同的糖果,每一种糖果都有自己的价值和重量.每箱糖果都可以拆分成任意散装组合带走.圣诞老人的驯鹿最多只能承受一定重量的糖果.请问圣诞老 ...
- K:哈弗曼树
相关介绍: 树形结构除了应用于查找和排序等操作时能调高效率,它在信息通讯领域也有着广泛的应用.哈弗曼(Huffman)树就是一种在编码技术方面得到广泛应用的二叉树,它同时也是一种最优二叉树. 哈弗曼 ...
- C#学习笔记-建造者模式
题目:用程序画一个小人. 实现: public partial class Form1 : Form { public Form1() { InitializeComponent(); } priva ...
- git 删除分支操作
删除分支时自己不能够在要删除的分支上 删除本地的某个分支 git branch -d branchname # 交互式删除分支 git branch -D branchname # 强制删除分支 删除 ...
- [搬运]在C#使用.NET设计模式的新观点
原文地址:http://www.dotnetcurry.com/dotnet/1092/dotnet-design-patterns 软件开发有许多设计模式.其中一些模式非常受欢迎.说几乎所有的模式都 ...
- deeplearning.ai 构建机器学习项目 Week 2 机器学习策略 II 听课笔记
1. 误差分析(Error analysis) 误差分析的目的是找到不同误差源的比重,从而指引我们接下来往哪个方向努力改进.NG建议手工统计随机100个错误的误差源,比如对于猫分类器,错误的照片可能是 ...
- bzoj 2303: [Apio2011]方格染色
传送门 Description Sam和他的妹妹Sara有一个包含n × m个方格的表格.她们想要将其的每个方格都染成红色或蓝色.出于个人喜好,他们想要表格中每个2 × 2的方形区域都包含奇数个(1 ...
- LibreOJ β Round #2 F. 数学上来先打表
传送门 题解 做法与题解基本无异,不过他说用vector我觉得用链表来得更好一些. #include<queue> #include<ctime> #include<bi ...
- 浅谈Windows环境下DOS及MS-DOS以及常见一些命令的介绍
浅谈Windows环境下DOS及MS-DOS以及常见一些命令的介绍 前记 自己是搞编程的,首先我是一个菜鸟,接触计算机这么久了,感觉很多计算机方面的技术和知识朦朦胧胧.模模糊糊,貌似有些贻笑大方了:所 ...
- java 跳出多层循环
lableB: for(int i=0;i<10;i++){ lableA: for(int j=0;j<10;j++){ System.out.println(j); if(j==1){ ...