概述

     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传参的更多相关文章

  1. Java传参那些事!

    刚刚学习java传参的时候很纠结,也非常的不理解!课本上的“按值传递”和“按址传递”搞的自己是一头雾水,后来写的项目多了,自然就明白了! 现在写传参几乎就是条件反射一般——“秒成”,分享当初自己为此写 ...

  2. Java传参都是传引用变量的副本

    最近做练习时碰到一个问题,Java到底是怎样传参的,经过查资料与实验,我发现Java传参都是传引用变量的副本值. 1 Java中的引用变量 1.1 字面值引用变量:即基本数据类型的引用变量 ,如 in ...

  3. java 传参方式--值传递还是引用传递

    java 传参方式--值传递还是引用传递 参数是按值而不是按引用传递的说明 Java 应用程序有且仅有的一种参数传递机制,即按值传递.写它是为了揭穿普遍存在的一种神话,即认为 Java 应用程序按引用 ...

  4. 使用java传参调用exe并且获取程序进度和返回结果的一种方法

    文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/ 1.背景 在某个项目中需要考虑使用java后台调用由C#编写的切图程序( ...

  5. Java传参-基本数据类型和引用数据类型作为参数的区别(值传递)

    java中的方法可以传递参数,参数的传递方法就是值传递. 参数有形参和实参,定义方法时写的参数叫形参,真正调用方法时,传递的参数叫实参. 调用方法时,会把实参传递给形参,方法内部其实是在使用形参. 所 ...

  6. String的按值传递,java传参都是传值

    java中对象作为参数传递给一个方法,到底是值传递,还是引用传递? String和int参数传递是按值传递还是引用传递? 一道面试题目,String的传递: public String change( ...

  7. Java传参

    1.  如果参数是基本数据类型(int.long等),传值.方法内部改变参数值,外部值不变. 2.  如果参数是对象类型,传地址.方法内部改变对象值,外部对象值改变.但是,如果方法内部调用new重新构 ...

  8. java传参问题

    参考链接:https://www.cnblogs.com/linkstar/p/5951141.html public class Example { String testString = publ ...

  9. Java传参:值传递 or 引用传递 ?

    刚开始学Java的时候一度以为:基本数据类型是值传递,引用类型是引用传递.新人很容易在这两个概念上面被搞糊涂,后来看了Hollis的文章才明白了Java中只有值传递. 接下来我能用简单明了的方式来说明 ...

随机推荐

  1. 掌握一门语言Go

    摘要:Go语言的优势不必多说,通过本篇文章,让我们花时间来掌握一门外语,Let's Go! 关键字:Go语言,闭包,基本语法,函数与方法,指针,slice,defer,channel,goroutin ...

  2. 前端基于react,后端基于.net core2.0的开发之路(番外篇) 后端使用T4模板,生成某些类

    1.介绍 因为开发过程中,有部分类是你加一个模型,就需要去改动的,每次加非常的烦,或者有些类,你只用到了他基类的方法,但是你还必须建一个文件才能调用他基类的方法,也很烦. 这个时候,T4就非常有用了. ...

  3. web安全与防御

    xss攻击(跨站脚本) 是网站应用程序的安全泄露攻击,是代码注入的一种.它允许恶意用户将代码注入到网页上,其他用户在观看网页时就会受到影响. 攻击原理 其特点是不对服务器端造成任何伤害,而是通过一些正 ...

  4. cs231n spring 2017 lecture7 Training Neural Networks II 听课笔记

    1. 优化: 1.1 随机梯度下降法(Stochasitc Gradient Decent, SGD)的问题: 1)对于condition number(Hessian矩阵最大和最小的奇异值的比值)很 ...

  5. 51 nod 1227 平均最小公倍数

    原题链接 Lcm(a,b)表示a和b的最小公倍数,A(n)表示Lcm(n,i)的平均数(1 <= i <= n), 例如:A(4) = (Lcm(1,4) + Lcm(2,4) + Lcm ...

  6. hdu_1010_Tempter of the Bone_dfs

    题意:给出一个地图,起点和终点,四通路(上下左右),问在一定的时间内可以走出这个地图吗 题解:首先这个题意一定要好好读,很容易读错题,理解成最短路径小于给定时间就可以出去,其实是不可以的,必须要在给定 ...

  7. NYoj_49开心的小明

    开心的小明 时间限制:1000 ms  |  内存限制:65535 KB 难度:4 描述 小明今天很开心,家里购置的新房就要领钥匙了,新房里有一间他自己专用的很宽敞的房间.更让他高兴的是,妈妈昨天对他 ...

  8. lombok使用基础教程

    前言 lombok是一个编译级别的插件,它可以在项目编译的时候生成一些代码.在很多工具类的项目中都有这个功能.比如dagger. 通俗的说,lombok可以通过注解来标示生成getter settte ...

  9. Oracle忘记密码如何重

    ---恢复内容开始--- 昨天安装Oracle11g R2的时候给scott用户设置密码,当时没有显示而且还只以输入一次,可能密码输入错误,结果今天用scott用户登录果然密码不对,还好sys和sys ...

  10. VIM 文件搜索与替换

    文件内搜索与替换 :[range]s/pattern/string/[c,e,g,i] 例如: :%s/oldword/newword/cg //对文本中全部匹配进行替换 :m,ns/oldword/ ...