java参数传递底层实现原理解析

1.如下代码最终输出为:???

这里就要说到java 传递参数的两种方式:值传递与引用传递.

1.值传递:方法调用时,实际参数把它的值传递给对应的形式参数,方法执行中形式参数值的改变不影响实际参 数的值。

2.引用传递:也称为传地址。方法调用时,实际参数的引用(地址,而不是参数的值)被传递给方法中相对应的形式参数,在方法执行中,对形式参数的操作实际上就是对实际参数的操作,方法执行中形式参数值的改变将会影响实际参数的值。

a.值传递的数据类型:八种基本数据类型(int, short, long, byte, float, double, boolean, char)和String(事实上String也是传递的地址,只是string对象和其他对象是不同的,string对象是不能被改变的,内容改变就会产生新对象,如下例子:)

1 String str="abc";
2 System.out.println(str);
3 str=str+"de";
4 System.out.println(str);

如果运行这段代码会发现先输出“abc”,然后又输出“abcde”,好像是str这个对象被更改了,其实,这只是一种假象罢了,JVM对于这几行代码是这样处理的,首先创建一个String对象str,并把“abc”赋值给str,然后在第三行中,其实JVM又创建了一个新的对象也名为str,然后再把原来的str的值和“de”加起来再赋值给新的str,而原来的str就会被JVM的垃圾回收机制(GC)给回收掉了,所以,str实际上并没有被更改,String对象一旦创建之后就不可更改了。所以,Java中对String对象进行的操作实际上是一个不断创建新的对象并且将旧的对象回收的一个过程,所以执行速度很慢。

顺便提一下String与StringBuffer的区别:

String为字符串常量,而StringBuilder和StringBuffer均为字符串变量,即String对象一旦创建之后该对象是不可更改的,但后两者的对象是变量,是可以更改的.

b.传递地址值的数据类型:除String及八种基础数据类型以外的所有复合数据类型,包括数组、类和接口 

所以,答案就很明显了,上两例分别输出:5和s  

那么问题来了,下面这两个例子该怎么输出呢?

分别输出(ss,s)和(2,1)

输出(ss,s)是因为s="ss"这句代码新建了对象s,JVM回收了原s字符串对象,而新建的x字符串对象在赋值时,赋的是原s字符串对象的值,所以会这样输出.

输出(2,1)是因为int 属于java基础数据类型,这里就要引入java里面堆栈的概念:

栈(stack)与堆(heap)都是Java用来在Ram中存放数据的地方。与C++不同,Java自动管理栈和堆,程序员不能直接地设置栈或堆。 

1.堆(heap)。一种通用性的内存池(存在于RAM中),用于存放所有的JAVA对象。堆不同于栈的地方是:编译器不需要知道要从堆里分配多少存储区 域,也不必知道存储的数据在堆里存活多长时间。因此,在堆里分配存储有很大的灵活性。当你需要创建一个对象的时候,只需要new写一行简单的代码,当执行 这行代码时,会自动在堆里进行存储分配。当然,为这种灵活性必须要付出相应的代码。用堆进行存储分配比用栈进行存储存储需要更多的时间。 在java中,所有使用new xxx()构造出来的对象都在堆中存储,当垃圾回收器检测到某对象未被引用,则自动销毁该对象.所以,理论上说java中对象的生存空间是没有限制的,只要有引用类型指向它,则它就可以在任意地方被使用. 

2.栈(stack)。位于通用RAM中,但通过它的“栈指针”可以从处理器那里获得支持。栈指针若向下移动,则分配新的内存;若向上移动,则释放那些 内存。这是一种快速有效的分配存储方法,仅次于寄存器。创建程序时候,JAVA编译器必须知道存储在栈内所有数据的确切大小和生命周期,因为它必须生成 相应的代码,以便上下移动堆栈指针, 这一约束限制了程序的灵活性; 栈 是一个先进后出的数据结构,通常用于保存方法(函数)中的参数,局部变量. 在java中,所有基本数据类型和引用类型都在栈中存储.栈中数据的生存空间一般在当前scopes内(就是由{...}括起来的区域). 

知道了这两个概念,我们再来分析上例的底层实现:

编译器先处理int s = 1;首先它会在栈中创建一个变量为s的引用,然后查找有没有字面值为1的地址,没找到,就开辟一个存放1这个字面值的地址,然后将s指向1的地址。接着处 理int x = s,此时s=1,于是编译器会在栈中创建一个变量为x的引用,然后将x指向1的地址; 再接着处理s=2,编译器会查找有没有字面值为2的地址,如果有直接指过去,如果没有就开辟一个存放2这个字面值的地址,然后将s指向2的地址,此时,s的值已经变了,但x的指向不会变,依然指向1这个地址, 通过字面值的引用来修改其值,不会导致另一个指向此字面值的引用的值也跟着改变.

所以结果就是s=2  x=1 了.

参照博文:https://blog.csdn.net/maoyeqiu/article/details/49250339 

参照博文:https://www.cnblogs.com/su-feng/p/6659064.html

参照博文:https://www.cnblogs.com/iliuyuet/p/5603618.html

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值