java参数传递内存图解,探讨Java参数传递问题
前言:
可能很多人都知道参数有形参和实参之分,却不知道区别到底是什么;知道Java中内存分为栈、堆、方法区等5片内存,不知道每片内存中保存的都是什么;关于参数的传递到底是值传递还是引用传递傻傻分不清楚。本文将为你逐一揭秘!
欢迎大家关注我的公众号 javawebkf,目前正在慢慢地将简书文章搬到公众号,以后简书和公众号文章将同步更新,且简书上的付费文章在公众号上将免费。
一、形参和实参:
形参:就是定义方法时,该方法携带的参数。比如定义如下方法:
public static void test(String name){
System.out.println(name);
}
test方法中的参数name就是形参,只有在test方法在被调用这个name的生命周期才开始,才会分配内存空间,当test方法调用完后,这个name也就不复存在。
实参:方法在被调用时实际传入的参数值,实参在方法调用前就已经被初始化。看例子:
public static void main(String[] args){
String name = "刘亦菲";
test(name);
}
这个String name = "刘亦菲"中这个name,在test方法被调用之前就就已被创建并且初始化,在调用test方法时,它就被当作实际参数传入,这就是实参。
二、Java中的内存:
Java中内存分为5片,分别是栈、堆、方法区、程序计数器、本地方法栈。
1、栈:
又称虚拟机栈。特点是先进后出。栈的线程是私有的,也就是线程之间的栈是隔离的。栈中有若干栈帧,每个栈帧对应一个方法。也就是说,当程序开始执行一个方法时,就会在栈中创建一个栈帧入栈,方法结束后,该栈帧出栈。看下面的图解:
栈与栈帧
每个栈帧主要包括:
局部变量表:存储方法中的局部变量。当局部变量是基本类型时,存储的是变量的值;当变量是引用类型时,存储的是地址值。
运行时常量池的引用:存储程序执行时可能会用到的常量的引用。
方法返回地址:存储方法执行完成后的返回地址。
2、堆:
堆内存用来存储对象和数组。数组以及所有new出来的对象都存储在堆内存中。在JVM中只有一个堆,所以堆是被所有线程共享的。
3、方法区:
方法区也是所有线程共享的区域,主要存储静态变量、常量池等。
三、数据在内存中的存储:
1、基本类型的存储:
基本类型的局部变量:变量以及数值都是存储在栈内存中。比如在某个方法中定义有如下局部变量:
int age = 6;
int grade = 6;
int weight = 50;
先创建一个age变量,存储在栈帧中的局部变量表,然后查找栈中是否有字面量值为6的内容,如果有,直接把age指向这个地址,没有开辟内存空间来存储"6"这个内容,同时让age指向它。当创建grade变量时,因为已经有字面量为"6"的内容了,所以直接拿过来用。所以栈中的数据在当前线程下是共享的。上面的代码在内存中的图解如下:
image.png
如果给age重新赋值:
age = 10;
难么就会在栈中查找是否有字面量为"10"的内容,有就直接拿来用,没有就开辟内存空间存储"10",然后age指向这个10。所以基本类型的变量,变量值本身是不会改变的,重新赋值后,只是指向了新的引用而已。
重新赋值
基本类型的成员变量:基本类型的成员变量的变量名和值都是存储在堆内存中的,其生命周期和对象是一致的。看下面的代码:
public class User{
private int age;
private String name;
private int grade;
......
}
调用:
User user = new User();
在内存中的存储图解:
User的存储
基本类型的静态变量:基本类型的静态变量存储于方法区的常量池中,随着类的加载而加载。
2、引用类型的存储:
通过上图可以发现,执行
User user = new User();
时分两个过程:
User user;// 定义变量
user = new User();// 赋值
定义变量时,会在栈中开辟内存空间存放user变量;赋值时会在堆内存中开辟内存空间存储User实例,这个实例会有一个地址值,同时把这地址值赋给栈中的user变量。所以引用类型的变量名存储在栈中,变量值存储的是堆中相对应的地址值,并不是存储的实际内容。
四、参数传递问题:
关于参数的传递,可能有点难理解,到底是值传递还是引用传递?下面一起来学习一下:
值传递:方法调用时,实际参数把它的值的副本传递给对应的形式参数,此时形参接收到的其实只是实参值的一个拷贝,所以在方法内对形参做任何操作都不会影响实参。看下面一段代码:
public class Test {
public static void test(int age,String name){
System.out.println("传入的name:"+name);
System.out.println("传入的age:"+age);
age = 66;
name = "张馨予";
System.out.println("方法内重新赋值的name:"+name);
System.out.println("方法内重新赋值的age:"+age);
}
public static void main(String[] args){
String name = "刘亦菲";
int age = 44;
test(age,name);//调用方法
System.out.println("方法执行后的name:"+name);
System.out.println("方法执行后的age:"+age);
}
}
执行结果如下:
运行结果
从结果可以发现,name和age在方法调用后并没有改变,所以传入方法的只是实参的拷贝。
引用传递:当参数是对象的时候,其实传递的对象的地址值,所以实参的地址值传给形参后,在方法内对形参进行操作会直接影响真实内容。看下面的代码:
定义对象:
@Data
public class User {
private String name;
private int age;
}
测试:
public class Test {
public static void userTest(User user){
System.out.println("传入的user:"+user);
user.setName("张馨予");
user.setAge(20);
System.out.println("方法内重新赋值的user:"+user);
}
public static void main(String[] args){
User user = new User();
user.setName("刘亦菲");
user.setAge(18);
userTest(user);//调用方法
System.out.println("方法执行后的user:"+user);
}
}
结果如下:
第一次运行结果
可以看到在方法内对user重新赋值,直接影响这个对象,所以方法执行完毕后输出的是修改后的user。
对上面的测试方法稍作修改:
public class Test {
public static void userTest(User user){
System.out.println("传入的user:"+user);
user = new User();//新增这行代码
user.setName("张馨予");
user.setAge(20);
System.out.println("方法内重新赋值的user:"+user);
}
public static void main(String[] args){
User user = new User();
user.setName("刘亦菲");
user.setAge(18);
userTest(user);//调用方法
System.out.println("方法执行后的user:"+user);
}
}
执行结果如下:
第二次运行结果
结果却是,方法执行后的user竟然没改变。
分析一下这两次的执行过程:
第一次:
第一次执行过程
第一次执行过程如上图,main方法进栈后,在堆中new了一个user对象x0001,然后调用userTest方法,userTest方法进栈,并且把user对象的地址值x0001传入userTest方法,所以在userTest方法中对user进行操作直接影响地址值为x0001的对象。所以就出现了第一次运行结果。
第二次:
第二次执行过程
第二次执行过程如上图,main方法进栈后,在堆中new了一个user对象x0001,然后调用userTest方法,userTest方法进栈,并且把user对象的地址值x0001传入userTest方法,在此之前都是和第一次一样的。接下来在该方法中有
user = new User();
到了这里,又在堆中new了一个user对象x0002,然后让栈中user变量指向新的user对象的地址值x0002。所以接下来在方法中对user的操作都是对地址值为x0002的对象的操作,自然不会影响到地址值为x0001的对象。所以就出现了第二次的运行结果。
小结:由上面的案例可以得出结论,基本类型传的是值的副本,引用类型传的是地址值,所以不论传的是引用类型还是基本类型,其实都是值传递。
总结:
本文介绍了形参与实参、Java中的内存以及各片内存主要存储哪些东西,最后讨论了一下参数传递问题。以上内容为个人理解,如果错误,欢迎批准指正!
java参数传递内存图解,探讨Java参数传递问题相关推荐
- Java的内存模型,java初级面试笔试题
我总结出了很多互联网公司的面试题及答案,并整理成了文档,以及各种学习的进阶学习资料,免费分享给大家. 扫描二维码或搜索下图红色VX号,加VX好友,拉你进[程序员面试学习交流群]免费领取.也欢迎各位一起 ...
- java内存问题怎么排查,java占内存高排查 java应用占用内存过高排查的解决方案...
想了解java应用占用内存过高排查的解决方案的相关内容吗,zhaixing_0307在本文为您仔细讲解java占内存高排查的相关知识和一些Code实例,欢迎阅读和指正,我们先划重点:java,占内存过 ...
- java ref object_深入探讨 java.lang.ref 包
概述 Java.lang.ref 是 Java 类库中比较特殊的一个包,它提供了与 Java 垃圾回收器密切相关的引用类.这些引用类对象可以指向其它对象,但它们不同于一般的引用,因为它们的存在并不防碍 ...
- java final 内存_聊聊 Java 内存模型
原标题:聊聊 Java 内存模型 *作者:青芒@有赞 本文目录 Java内存模型 重排序 内存屏障 volatitle的内存语义 final的内存语义 一.Java内存模型 硬件处理 电脑硬件,我们知 ...
- java 自定义报表_图解自定义java报表菜单实现五大步
1.写一个Java文件如SaveReportAction所示,其包名为com.demo,编译这个Java文件为类文件,保存到设计器的classpath下面.代码如下: package com.demo ...
- linux java 进程内存_linux – 在java进程中消耗内存的是什么?
我们正在尝试在中等负载下研究 java进程的内存使用情况. PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 12663 test 20 0 ...
- linux查看java虚拟机内存_JVM:查看java内存情况命令
jmap (linux下特有,也是很常用的一个命令) 观察运行中的jvm物理内存的占用情况. 参数如下: -heap :打印jvm heap的情况 -histo: 打印jvm heap的直方图.其输出 ...
- java visualvm 内存_【Java线程与内存分析工具】VisualVM与MAT简明教程
前言 本文将简要介绍Java线程与内存分析工具VisualVM和MAT的使用,进一步的学习可参考官网或工具帮助(例如MAT:Help -> Welcome -> Tutorials),并在 ...
- java vector内存结构_4. Java集合知识测试
集合部分测试题 考试宣言: 同学们, 考试考多少分不是我们的目的! 排在班级多少的名次也不是我们的初衷! 我们考试的目的是要通过考试中的题目,检查大家在这段时间的学习中,是否已经把需要掌握的知识掌握住 ...
- java虚拟机内存比例,【Java虚拟机】堆内存分配策略总结
1 一般情况 对象出生在Eden区. 第一次MinorGC之后仍然存活,并且能被Survivor容纳,则被移动到Survivor空间中,并将年龄设为1. 对象在Survivor区中每熬过一次Minor ...
最新文章
- Nat. Commun. | msiPL:质谱数据分析的新工具
- DHCP服务器的搭建与维护
- Spring Aop实例之AspectJ注解配置
- 腾讯面试:打家劫舍 III
- James 3.0 邮箱配置
- ios15之取消UITabbleViewCell的高亮效果
- 自然场景下的文字检测:从多方向迈向任意形状
- Flume-ng HDFS sink原理解析
- h5离线缓存与浏览器缓存的区别
- [老文章搬家] 插件化软件设计的头疼问题以及可能的解决思路
- 【转载】快逸报表问题
- E盾V60原版网络验证包含个人动手改IP地址源码软件加密一机一码
- 云计算系统典型物理架构
- mysql合并两个表_MYSQL如何合并两个表
- 微博有哪些营销价值?
- 香港中文大学推荐大学期间书单 87本你读过哪些?
- 数学建模论文的技巧与操作
- 手机安装linux发行版,为亲朋好友挑选一款合适的Linux发行版
- 【笔记】lua - 协程
- 下载本地pdf并压缩为zip文件
热门文章
- requests、xpath应用案例
- 小米盒子3显示无网络连接服务器,小米盒子不显示无线网络连不上 - 卡饭网
- 国内缺少一个slideshare
- 基本的常见的锁的介绍
- 数字图像处理之简单 JPEG图片压缩
- 3D游戏场景模型制作的细节与技巧
- 转载《五大免费采集器哪个好,火车头,海纳,ET,三人行,狂人采集 》
- python父亲节祝福_关于父亲节的祝福语大全(27句),暖心的句子
- js java script MD5码的生成
- windows上未关闭135、445等危险端口引发的威胁