关键词:
值传递和引用传递分析
Java中数据类型分为两大类:基本类型和引用类型(也就是对象类型)。
基本类型:boolean、char、byte、short、int、long、float、double
引用类型:类、接口、数组
因此,变量类型也可分为两大类:基本类型和引用类型。
在分析值传递和引用传递之前,建议了解下以上变量类型在Java内存管理模型中的位置,如果对此有所了解,将更加有助于理解两种传递的方式^_^
在Java内存中,基本类型变量存储在Java栈(VM Stack)中,引用变量存储在堆(Heap)中,模型如下:
值传递和引用传递的定义:
这里要用实际参数和形式参数的概念来帮助理解
值传递:方法调用时,实际参数把它的值传递给对应的形式参数,函数接收的是原始值的一个 copy,此时内存中存在两个相等的基本类型,即实际参数和形式参数,后面方法中的操作都是对形参这个值的修改,不影响实际参数的值。
引用传递:
也称为传地址。方法调用时,实际参数的引用(地址,而不是参数的值)被传递给方法中相对应的形式参数,函数接收的是原始值的内存地址;在方法执行中,形参和实参内容相同,指向同一块内存地址,方法执行中对引用的操作将会影响到实际对象。 demo1:
值传递:
public static void main(String[] args)
System.out.println(" 值传递测试 ");
int a = 10;
int b = 20;
System.out.println("before swap " + "a = " + a + " b = " + b);
swap(a, b);
System.out.println("after swap " + "a = " + a + " b = " + b);
public static void swap(int a, int b)
int temp = a;
- = b;
- = temp;
System.out.println("swaping " + "a = " + a + " b = " + b);
before swap a = 10 b = 20 swaping a = 20 b = 10 after swap a = 10 b = 20
从jvm的角度来理解的话,因为main也是一个方法,所以这个时候基本数据类型也是在栈中的,
假如是全局的话就会在堆中。要想理解基本数据类型的值传递我们首先来回顾一下jvm加载数据的过程,
从上面的例子我们看到,首先jvm会把class的相关信息放到方法区中,当代码执行到int a=10和int b=20的时候会把这些信息放到栈中去也就是局部变量表中去。这个时候在栈中的基本数据类型它本身就是真身,现在假如把它传到方法中进行对值进行操作的话,jvm规定就会复制一份数据出来,这个时候操作的就是数据复制的信息。而假如是引用数据类型的话,我们来看下面的案例
public class ParamTest
public static void main(String[] args)
Student a = new Student(0);
Student b = new Student(100);
System.out.println("交换前:");
System.out.println("a的分数:" + a.getScore() + "--- b的分数:" + b.getScore());
swap(a, b);
System.out.println("交换后:");
System.out.println("a的分数:" + a.getScore() + "--- b的分数:" + b.getScore());
public static void swap(Student x, Student y)
x.setScore(99);
y.setScore(99);
交换前:
a的分数:0.0--- b的分数:100.0 交换后:
a的分数:99.0--- b的分数:99.0
我们再来看看引用数据类型的jvm的加载过程,首先当jvm类加载器加载class文件的时候会把所有的信息都放到方法区中,这个时候当加载到Student a = new Student(0); Student b = new Student(100);的时候会把a,b如栈,这个时候a.b只是引用的而真正的两个 student都在堆中,a和b只不过是化身而已,这个时候我们假如对化身a和b进行操作的话,它a和b本身就是对堆中的引用地址的代表,a和b这个时候就代表student在堆中的内存地址,所以这个时候假如对a和b进行操作的话就是对堆中的对象进行操作,所以会引起值的变化。
理解了上面的值传递和引用传递我们再来看看下面的案例
public static void main(String[] args)
System.out.println(" 值传递测试 ");
int a = 10;
int b = 20;
System.out.println("before swap " + "a = " + a + " b = " + b);
swap(a, b);
System.out.println("after swap " + "a = " + a + " b = " + b);
public static void swap(int a, int b)
- = 1;
- = 1;
System.out.println("swaping " + "a = " + a + " b = " + b);
before swap a = 10 b = 20 swaping a = 1 b = 1
after swap a = 10 b = 20
道理就是值传递,我们主要是为了引出下面的例子 public static void main(String[] args)
Student a = new Student(0);
Student b = new Student(100);
System.out.println("交换前:");
System.out.println("a的分数:" + a.getScore() + "--- b的分数:" + b.getScore());
swap(a, b);
System.out.println("交换后:");
System.out.println("a的分数:" + a.getScore() + "--- b的分数:" + b.getScore());
public static void swap(Student x, Student y)
x=new Student(99);
y=new Student(99);
交换前:
a的分数:0.0--- b的分数:100.0
交换后:
a的分数:0.0--- b的分数:100.0
从上面我们可以看到本来a和b都分别指向堆中的new student(0)和student(10)的现在在另一个方法中现在又有x和y指向了堆中的new student(99)和new student(99)所以这个时候a和b的引用地址还是不变的,只不过是xy的变化了而已。本质是a和b分别指向了两个不同的堆内存空间
我们在来看final的例子
public static void main(String[] args)
// String、Char、Byte、Short、Integer、Long、Float、Double等final修饰的类
// 对形参修改时实参不受影响
System.out.println(" final修饰的类-特殊的引用传递测试 ");
String str = "我是final我不变"; swapByFinalClass(str);
System.out.println("after swapByFinalClass, str = " + str);
/**
* final修饰的类做形参时, 修改形参不影响实参
*/
public static void swapByFinalClass(String str)
str = "我是形参";
System.out.println("swapByFinalClassing : str = " + str);
final修饰的类-特殊的引用传递测试
swapByFinalClassing : str = 我是形参 after swapByFinalClass, str = 我是final我不变
只不过这个时候数据放在了方法区的常量池中了,而不是在堆中了。
1)使用基本类型的变量a、b通过swap方法进行的是值传递,对形参修改但实参未改变,
利用内存模型详解原理:
2)使用类ReferenceObj的实例变量obj,通过swapByReference()进行的是引用传递的方式,具体的内存模型如下:
通过上面的分析,对于传递方式应该很好理解了^_^
注意:这里要特殊考虑String,以及Integer、Double等基本类型包装类,它们的类前面都有final修饰,为不可变的类对象,每次操作(new或修改值)都是新生成一个对象,对形参的修改时,实参不受影响,与值传递的效果类似,但实际上仍是引用传递。
总结:
- 基本类型变量作为方法中的参数,进行的值传递,对形参的修改不影响实参的原来的值;
- 非final修饰的类、数组、接口作为方法中的参数,进行的引用传递(地址传递),对形参修改后实参也会改变,因为二者指向的是同一个实例;
- final修饰的类作为方法中的参数,因为final的存在初始化后值不可变,每次操作都相当于产生一个新的实例对象,因此对形参修改时,实参也不受影响。
jvm基础--jvm内存模型
jvm基础–JVM内存模型文章目录jvm基础--JVM内存模型1.JVM内存模型1.JVM内存模型参考:深入理解JVM-JVM内存模型面试必问之JVM原理深入理解JVM-内存模型(jmm)和GC 查看详情
jvm基础--jvm内存模型
jvm基础–JVM内存模型文章目录jvm基础–JVM内存模型1.JVM内存模型1.JVM内存模型参考:深入理解JVM-JVM内存模型面试必问之JVM原理深入理解JVM-内存模型(jmm)和GC 查看详情
深入理解jvm——jvm内存模型
JVM内存模型Java虚拟机(JavaVirtualMachine=JVM)的内存空间分为五个部分,分别是: 1.程序计数器 2.Java虚拟机栈 3.本地方法栈 4.堆 5.方法区。下面对这五个区域展开深入的介绍。 1.程序计数器1.1.什么是程序计数器... 查看详情
打怪升级jvm关于jvm内存模型及gc调优(代码片段)
JVM调优,其实就是调整SWT和FGC的过程 JVM内存模型 通过一张基础的图了解最简单的JVM模型: 其实在jvm模型中,主要包含了我们常见的堆栈方法区等待--每个版本不同可能解释有所不同,这里默认以8版本为例: ... 查看详情
深入理解jvm—jvm内存模型
原文地址:http://www.lofter.com/app/QRCodedownload?act=qbbkdlxz_20150313_13我们知道,计算机CPU和内存的交互是最频繁的,内存是我们的高速缓存区,用户磁盘和CPU的交互,而CPU运转速度越来越快,磁盘远远跟不上CPU的读写速度,才设计了内... 查看详情
深入理解jvm—jvm内存模型
http://www.cnblogs.com/dingyingsi/p/3760447.html#3497199我们知道,计算机CPU和内存的交互是最频繁的,内存是我们的高速缓存区,用户磁盘和CPU的交互,而CPU运转速度越来越快,磁盘远远跟不上CPU的读写速度,才设计了内存,用户缓冲用户I... 查看详情
(转)深入理解jvm—jvm内存模型
原文地址:http://www.cnblogs.com/dingyingsi/p/3760447.html我们知道,计算机CPU和内存的交互是最频繁的,内存是我们的高速缓存区,用户磁盘和CPU的交互,而CPU运转速度越来越快,磁盘远远跟不上CPU的读写速度,才设计了内存,用户缓冲... 查看详情
深入理解jvm—jvm内存模型
我们知道,计算机CPU和内存的交互是最频繁的,内存是我们的高速缓存区,用户磁盘和CPU的交互,而CPU运转速度越来越快,磁盘远远跟不上CPU的读写速度,才设计了内存,用户缓冲用户IO等待导致CPU的等待成本,但是随着CPU的发... 查看详情
深入理解jvm—jvm内存模型
我们知道,计算机CPU和内存的交互是最频繁的,内存是我们的高速缓存区,用户磁盘和CPU的交互,而CPU运转速度越来越快,磁盘远远跟不上CPU的读写速度,才设计了内存,用户缓冲用户IO等待导致CPU的等待成本,但是随着CPU的发... 查看详情
jvm内存模型理解
Java虚拟机(JavaVirtualMachine简称JVM)是运行所有Java程序的抽象计算机,是Java语言的运行环境,它是Java最具吸引力的特性之一。JVM内存模型 1.方法区和堆是所有线程共享的数据区1)堆:存放对象的实例2)方法区:存放已被虚... 查看详情
jvm内存模型的理解
今天周六,又开始啃一遍《深入理解java虚拟机》每次读的感觉不一样,大学代码量较少,读起来也就死记硬背。1.堆:长度可变,运行时使用的变量;存放对象(new)和数组之类;2.栈:长度可变,在分配内存之前,固定了其大... 查看详情
jvm——内存模型
这是我理解的jvm内存模型,这一整块可以简单理解为虚拟内存空间:jvm代码、jvm数据:是运行jvm所用到的代码和数据,并不是我们自己编程得到的代码和数据directmemory:主要是NIO在使用CodeCache:即时编译器生成的本地代码JNI代码... 查看详情
深入理解jvm内存结构-垃圾回收-类加载&字节码技术-内存模型(代码片段)
资料下载内容参考一、什么是JVM?JVM(JavaVirtualMachine)其实就类似于一台小电脑运行在windows或者linux这些操作系统环境下。它直接和操作系统进行交互,与硬件不直接交互,然后操作系统可以帮我们完成和硬... 查看详情
深入理解jvm内存结构-垃圾回收-类加载&字节码技术-内存模型(代码片段)
资料下载内容参考一、什么是JVM?JVM(JavaVirtualMachine)其实就类似于一台小电脑运行在windows或者linux这些操作系统环境下。它直接和操作系统进行交互,与硬件不直接交互,然后操作系统可以帮我们完成和硬... 查看详情
jvm-内存模型
本篇其实就是一个读书笔记,书是《深入理解JAVA虚拟机》,在网上搜索JAVA内存,说的比较好的其实很多都源自这本书,作为一个JAVA程序员,理解虚拟机是通向高级程序员的必经道路。本篇中的图片源自当时网上,具体出处找不... 查看详情
深入理解jvm
深入理解JVM原文链接:https://www.cnblogs.com/dingyingsi/p/3760447.html整理:CCSoft 虚拟机内存模型中定义的访问操作如下图所示:图1.JVM虚拟机定义的访问操作java中通过多线程机制使得多个任务同时执行处理,所有的线程共享JVM内存... 查看详情
jvm运行时内存划分
(根据《深入理解java虚拟机》这本书总结) 本文主要解释jvm内存模型,以及各个部分的作用。都是自己总结的给自己看的通俗语言,未用专业术语的见谅。 一、为什么要了解jvm内存模型? 在了解一个类的编译-... 查看详情
深入理解jvm内存模型
我们知道,计算机CPU和内存的交互是最频繁的,内存是我们的高速缓存区,用户磁盘和CPU的交互,而CPU运转速度越来越快,磁盘远远跟不上CPU的读写速度,才设计了内存,用户缓冲用户IO等待导致CPU的等待成本,但是随着CPU的发... 查看详情