简单谈谈Java中的栈和堆
作者:巴黎爱工作 发布时间:2022-07-30 05:33:01
人们常说堆栈堆栈,堆和栈是内存中两处不一样的地方,什么样的数据存在栈,又是什么样的数据存在堆中?
这里浅谈Java中的栈和堆
首先,将结论写在前面,后面再用例子加以验证。
Java的栈中存储以下类型数据,栈对应的英文单词是Stack
基本类型
引用类型变量
方法
栈的优势是,存取速度比堆要快,仅次于寄存器,栈数据可以共享。但缺点是,存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。
栈中主要存放一些基本类型的变量(int, short, long, byte, float, double, boolean, char)和对象句柄。
栈有一个很重要的特殊性,就是存在栈中的数据可以共享。
Java的堆中存储以下类型数据,堆对应的英文单词是Heap
实例对象
在函数中定义的一些基本类型的变量(8种)和对象的引用变量都是在函数的栈Stack内存中分配。当在一段代码块中定义一个变量时,java就在栈中为这个变量分配内存空间,当超过变量的作用域后,java会自动释放掉为该变量分配的内存空间,该内存空间可以立刻被另作他用。
堆Heap内存用于存放由new创建的对象和数组。在堆中分配的内存,由java虚拟机自动垃圾回收器来管理。在堆中产生了一个数组或者对象后,还可以在栈中定义一个特殊的变量,这个变量的取值等于数组或者对象在堆内存中的首地址,在栈中的这个特殊的变量就变成了数组或者对象的引用变量,以后就可以在程序中使用栈内存中的引用变量来访问堆中的数组或者对象,引用变量相当于为数组或者对象起的一个别名,或者代号。
引用变量是普通变量,定义时在栈中分配内存,引用变量在程序运行到作用域外释放。而数组&对象本身在堆中分配,即使程序运行到使用new产生数组和对象的语句所在地代码块之外,数组和对象本身占用的堆内存也不会被释放,数组和对象在没有引用变量指向它的时候,才变成垃圾,不能再被使用,但是仍然占着内存,在随后的一个不确定的时间被垃圾回收器释放掉。这个也是java比较占内存的主要原因,实际上,栈中的变量指向堆内存中的变量,这就是 Java 中的指针!
class Person {
int age;
}
public class LearnHeap {
public static void main(String args[]){
int a=10;
Person person = new Person();
person.age =20;
change(a,person);
System.out.println("a="+ a+",and person.age = "+person.age);
}
static void change(int a1, Person person){
a1 = 11;
person.age= 21;
System.out.println("a1="+ a1+",and age1 = "+person);
}
}
两次的输出结果是什么?猜测下。
以上程序内存加载的执行步骤:
第1步 —— main()函数是程序入口,JVM先执行,首先将main方法压入栈中,在栈内存中开辟一个空间,存放int类型变量a,同时附值10。
在堆中分配一片区域,用来存放和创建Person对象,这片内存区域会有属于自己的内存地址,假设是1001,然后给成员变量赋值,age=20
执行结束后,构造防范弾栈,Person创建完成,将Person的内存地址1001赋值给person(此处person小写,是引用变量类型)
第2步 —— JVM执行change()函数,在栈内存中又开辟一个新的空间,存放int类型变量a和对象Person中person
此时main空间与change空间并存,同时运行,互不影响。
第3步 —— change()方法执行,将a赋值为11,person对象的堆中年龄age赋值为21
第4步 —— change()执行完毕,变量a立即释放,空间消失。但是main()函数空间仍存在,main中的变量a仍然存在,不受影响。而person在堆中对应的地址,所指的age已经赋值=21
实际输出如下:
结论:
如果a()方法中的基本类型(8个)变量x传入b()方法中,并在b()中进行了修改,则a()方法中的x的值保持不变
如果a()方法中的引用类型 变量x传入b()方法中,并在b()中进行了修改,则a()方法中的x的值与b()保持一致
下面对8中基本类型进行简单的测试
package heapandStack;
public class LearnHeap02 {
public static void main(String args[]){
byte b=10;
short s=20;
int i=30;
long l =40l;
float f =12.34f;
double d = 100.123d;
char c = 'A';
boolean flag = true;
change(b,s,i,l,f,d,c,flag);
System.out.println(b);
System.out.println(s);
System.out.println(i);
System.out.println(l);
System.out.println(f);
System.out.println(d);
System.out.println(c);
System.out.println(flag);
}
static void change(byte a, short b, int c,long d, float f, double g, char h,boolean x){
a =11;
b=21;
c =31;
d =41l;
f=12.99f;
g= 200.123d;
h ='V';
x =false;
System.out.println(a);
System.out.println(b);
System.out.println(c);
System.out.println(d);
System.out.println(f);
System.out.println(g);
System.out.println(h);
System.out.println(x);
}
}
下面测试一下数组,是不是属于实例对象类型
public class LearnHeap03 {
public static void main(String args[]){
int a[] ={1,2,3};
change(a);
for(int i:a)
System.out.print(i+" ");
}
static void change(int[] a){
a[0]=4;
a[1]=5;
for(int i:a)
System.out.print(i+" ");
System.out.println("============ ");
}
}
从结果看出,数组的值被改变了
Java种8种基本数据类型,并不包含String,String的值会被change函数改变吗?String应该存在栈中,还是堆中呢?
先直接上测试代码
public class Learn04 {
public static void main(String args[]){
String s1 = new String("abcd");
String s2 = "asdfghjkl";
System.out.println(s1+", "+s2);
change(s1,s2);
System.out.println(s1+", "+s2);
}
static void change(String s1,String s2){
s1 ="123456";
s2 ="000000";
System.out.println(s1+", "+s2);
}
}
两种的形式来创建String,第一种是用new()来新建对象的,它会在存放于堆中。每调用一次就会创建一个新的对象。 而第二种是先在栈中创建一个对String类的对象引用变量s2,然后查找栈中有没有存放"asdfghjkl",如果没有,则将"asdfghjkl"存放进栈,并令str指 向”abc”,如果已经有”asdfghjkl” 则直接令s2指向“asdfghjkl”。
既然讲到两种形式创建String,下面讲一个String两种形式创建的区别,先看一段代码
public class Learn05 {
public static void main(String args[]){
String s1 = new String("abcd");
String s2 = "abcd";
boolean a =s1.equals(s2);
boolean b =(s1==s2);
System.out.println(a);
System.out.println(b);
String s3 = "abcd";
boolean a1 =s3.equals(s2);
boolean b1 =(s3==s2);
System.out.println(a1);
System.out.println(b1);
}
}
总结
来源:https://www.cnblogs.com/qianjinyan/p/10352749.html
猜你喜欢
- 前文本章是关于Java流程控制语句的最全汇总,本篇为汇总中篇。流程是人们生活中不可或缺的一部分,它表示人们每天都在按照一定的流程做事。比如出
- 在项目开发中,我们经常会遇到表中的字段名和表对应实体类的属性名称不一定都是完全相同的情况,下面小编给大家演示一下这种情况下的如何解决字段名与
- 经过几天的折腾,终于到了学习一个重量级的查询方式上,使用@Query注解,使用注解有两种方式,一种是JPQL的SQL语言方式,一种是原生SQ
- 记得在thinkphp框架中,模型名会自动转换为对应下划线的表名,如,UserType 自动转化为user_type,在平时写程序中很多地方
- 一,使用注解: 在spring的配置文件applicationContext.xml中,加入注解扫描。配
- 采用继承Thead类实现多线程:优势:编写简单,如果需要访问当前线程,只需使用this即可,无需使用Thead.currentThread(
- 循环队列结构队列特点队列为一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,
- 前言Hello!上一期我大致讲解了关于Collection单列集合以及它的子接口List集合的概述、特点和遍历等,今天我为大家讲解关于Col
- 1.多数据源配置类整体项目结构1).pom.xml 项目依赖<?xml version="1.0" encodin
- 详解Java注解的实现与使用方法Java注解是java5版本发布的,其作用就是节省配置文件,增强代码可读性。在如今各种框架及开发中非常常见,
- 这几天自己研究了关于地手机上面开发安卓地图的问题,发现百度官方示例demo讲解百度持续定位方面还是讲解的有些不清楚,本人研究了几次之后将其弄
- 最近研究了一下如何在Android上实现CoverFlow效果的控件,其实早在2010年,就有Neil Davies开发并开源出了这个控件,
- 本文实例为大家分享了java实现猜数字游戏的具体代码,供大家参考,具体内容如下随机生成0~100的数字,通过控制台输入猜测数字,输出进行提示
- 前言大家好,我是bigsai,在数据结构与算法中,二叉树无论是考研、笔试都是非常高频的考点内容,在二叉树中,二叉树的遍历又是非常重要的知识点
- 本文实例讲述了java实现简单的英文文本单词翻译器功能。分享给大家供大家参考,具体如下:直接上代码:package fanyi;import
- 一、容器初始化1、源码分析在jdk8的ConcurrentHashMap中一共有5个构造方法,这四个构造方法中都没有对内部的数组
- 目录Sonar概述一、 搭建sona服务二、idea配置三、 配置maven的setting.xml文件四、idea中 mvn sonar:
- Android的应用被限制为最多占用16m的内存,至少在T-Mobile G1上是这样的(当然现在已经有几百兆的内存可以用了——译者注)。它
- 1、一个示例回顾Future一些业务场景我们需要使用多线程异步执行任务,加快任务执行速度。JDK5新增了Future接口,用于描述一个异步计
- 1、原理事务的概念想必大家都很清楚,其ACID特性在开发过程中占有重要的地位。同时在并发过程中会出现一些一致性问题,为了解决一致性问题,也出