作一个积极的人java
编码、改bug、提高本身编程
我有一个乐园,面向编程,春暖花开!设计模式
推荐阅读数组
第一季
0、Java的线程安全、单例模式、JVM内存结构等知识梳理安全
二、Java内存管理-初始JVM和JVM启动流程(二)多线程
三、Java内存管理-JVM内存模型以及JDK7和JDK8内存模型对比总结(三)学习
四、Java内存管理-掌握虚拟机类加载机制(四)this
七、Java内存管理-掌握自定义类加载器的实现(七)
第一季总结:由浅入深JAVA内存管理 Core Story第二季
九、Java内存管理-”一文掌握虚拟机建立对象的秘密”(九)
十、Java内存管理-你真的理解Java中的数据类型吗(十)
十一、Java内存管理-Stackoverflow问答-Java是传值仍是传引用?(十一)
十二、Java内存管理-探索Java中字符串String(十二)
实战
分享一位老师的人工智能教程。零基础!通俗易懂!风趣幽默!你们能够看看是否对本身有帮助,点击这里查看【人工智能教程】。接下来进入正文。
勿在流沙筑高台,出来混早晚要还的。
本文导图:
分享一位老师的人工智能教程。零基础!通俗易懂!风趣幽默!你们能够看看是否对本身有帮助,点击这里查看【人工智能教程】。接下来进入正文。
@[toc]
在Stack Overflow
看到这样一个问题:
Is Java “pass-by-reference” or “pass-by-value”?
翻译成中文:
Java是传值仍是传引用?
请先不要看下面的内容,思考10秒后,在继续阅读!!!
为何建议先思考,在阅读内容呢?
咱们天天可能会利用碎片化的时间阅读不少内容,有不少信息和知识其实在大脑过一下,而后就忘记了!如何才能高效的利用碎片化时间掌握或者记住更多的内容和知识,我本身碎片化阅读的理解和技巧:阅读一篇本身感兴趣技术文章,在时间容许的时间下,必定是一次性阅读完,在阅读中带着本身的问题,阅读后有本身的简单总结。 千万不要阅读 一段内容,看到微信有人发消息给你,就切换聊天框回复消息,而后回复完再切换回来阅读技术文章。这种 大脑 的切换是须要耗费资源的,也影响阅读的效果和效率(大脑在多个任务切换相似cpu多线程调度,线程的频繁切换。就如多线程不必定能提供效率,频繁的线程/任务切换耗费cpu大量资源)!
扯远 了,切换回到本文正题,Java是传值仍是传引用?
我相信你阅读完本篇后必定可以回答上面的问题,而且在工做在写相似传参的代码也会有更深刻的理解。开启探索之旅,Let's go!
在Java程序中会包含方法,方法会分为方法声明和方法实现,在方法声明中又有参数列表,参数根据调用后的效果不一样,也就是是否改变参数的原始值,能够划分为两种: 按值传递参数和按引用传递参数。
也就是以前介绍过的Java的基本类型和引用类型,若是方法参数中传递的基本类型就认为是 按值传递(传值),方法参数中传递的是引用类型,就称之为按引用传递(传引用)。
一段简单的代码:
public class PrettyGirl {
/**
* 芳龄几何
*/
int age;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public static void main(String[] args) {
// 引用类型
PrettyGirl prettyGirl = new PrettyGirl();
prettyGirl.setAge(28);
// 基本类型
int num = 50;
// 数组arrs也引用类型
int[] arrs = new int[]{2,0,1,9};
System.out.println("mian 中 num = " + num);
System.out.println("mian 中 arrs[3] = " + arrs[3]);
System.out.println("mian 中 prettyGirl.getAge() = " + prettyGirl.getAge());
System.out.println("-----------------------------------------");
// 调用 change方法
prettyGirl.change(num, arrs, prettyGirl);
System.out.println("调用change 后 mian 中 num = " + num);
System.out.println("调用change 后 mian 中 arrs[3] = " + arrs[3]);
System.out.println("调用change 后 mian 中 prettyGirl.getAge() = " + prettyGirl.getAge());
}
public void change(int pnum, int[] parrs, PrettyGirl ppg) {
//在change中 改变值类型pnum的值
pnum = pnum + 50;
//在change中 改变引用类型 parrs,ppg 的值
parrs[3] = 8;
// 从28变18
ppg.setAge(18);
System.out.println("change 中 pnum = " + pnum);
System.out.println("change 中 parrs[3] = " + parrs[3]);
System.out.println("change 中 ppg.getAge() = " + ppg.getAge());
System.out.println("-----------------------------------------");
}
}复制代码
思考一下,打印的结果是什么?
打印结果以下:
mian 中 num = 50
mian 中 arrs[3] = 9
mian 中 prettyGirl.getAge() = 28
-----------------------------------------
change 中 pnum = 100
change 中 parrs[3] = 8
change 中 ppg.getAge() = 18
-----------------------------------------
调用change 后 mian 中 num = 50
调用change 后 mian 中 arrs[3] = 8
调用change 后 mian 中 prettyGirl.getAge() = 18复制代码
下面开启分析之旅,结合以前学过的Java内存模型来画上面代码执行的内存变化的图
注:下图只是为了演示讲解说明,真实内存地址不必定是这样!
int 类型变量num在栈中分配一块内存,而 parrs 与 ppg 分配两块内存,栈中一块,堆中一块。当调用change方法时,建立三个变量 pnum,parrs,ppg这里至关于把栈中的数据全备份一份给这三个数值,则有
在change方法中对传递的参数进行修改,此时pnum的值修改成 100,堆中ppg指向的对象年龄由28改成18,数组中parrs[3]修改成8。也就是 ppg与 parrs 改变了堆中的具体数值,而 pnum 改变的只是栈中的数值。
最后,当change方法调用结束,change栈帧被弹出,则对应的pnum,ppg,parrs 三个变量也消亡,此时只有main栈帧状况以下图:
经过上图的演示,上面代码的打印结果就很清晰明了了。
tips:回顾 java 栈
Java栈中存放的是一个个的栈帧,每一个栈帧对应一个被调用的方法,在栈帧中包括局部变量表(Local Variables)、操做数栈(Operand Stack)、指向当前方法所属的类的运行时常量池(运行时常量池的概念在方法区部分会谈到)的引用(Reference to runtime constant pool)、方法返回地址(Return Address)和一些额外的附加信息。当线程执行一个方法时,就会随之建立一个对应的栈帧,并将创建的栈帧压栈。当方法执行完毕以后,便会将栈帧出栈。所以可知,线程当前执行的方法所对应的栈帧一定位于Java栈的顶部。
根据上面例子中这样的内存变换,想必你应该知道按值传递与按引用传递的深层缘由了吧!
从上图中看全部的参数传递 本质都是按址值传递, 也就是内存地址的值 。 基本类型由于栈内存地址中保存就是其自己值,全部在参数传递的时候,拷贝自己的值进行传递,而引用类型在栈内存地址中保存的是引用的值,经过栈内存保存引用的值指向堆中获取对象真是的值,在参数传递的时候,拷贝的是引用的值。
全部在方法传递参数后,若是基本类型的值在传递的方法中有修改,不会影响传递前方法中的值。而引用类型就不一样了,由于它修改的是引用地址指向堆中数据,这部分数据在参数传递的时候不会拷贝一份,就如上面图解标识出的同样。
在Java中,对象经过引用传递,基本类型按值传递。
这句话的描述有一半是不许确的。就如上面咱们图中看到的那样基本类型是按照值传递的; 引用类型是拷贝引用的址值传递的,也即对象不经过引用传递。正确的描述语句是对象引用也是按值传递。
其实在Java语言规范(JLS)中描述:Java 严格按值传递,能够理解与C彻底相同,也就是Java中参数传递的本质是按址值传递。
若是你在阅读完本篇后,对上面问题有本身的深刻的理解,有欢迎文末留言一块儿探讨!
备注: 因为本人能力有限,文中如有错误之处,欢迎指正。
Is Java “pass-by-reference” or “pass-by-value”?
Java is Pass-by-Value, Dammit!
谢谢你的阅读,若是您以为这篇博文对你有帮助,请点赞或者喜欢,让更多的人看到!祝你天天开心愉快!