前言
最近实习生招聘面试,喜欢问jvm的存储结构,这个大家基本都能回答出来(八股文背诵的嫌疑),但是问了几个具体的case,就很多同学都回答不出来或者很模糊。
所以同学们真的了解数据类型在jvm中的存储么?
举例如下:
int a1 = 1;
Integer a2 = 1;
Integer a3 = 128;
Integer a4 = 128;
System.out.println(a1==a2);
System.out.println(a3==a4);
String s1 = "china";
String s2 = new String("china");
一、基础知识
1.1、变量的分类
成员变量:定义在类中方法(代码块)外的变量。
使用static修饰的成员变量: 静态成员变量位于方法区中(详细请看下文),是类级别的。
未使用static修饰的成员变量:实例成员变量位于堆空间中(详细请看下文),是对象级别的。
局部变量 :除成员变量外都是局部变量位于方法所在的栈帧中(详细请看下文),是方法级别的。
1.2、JVM的存储结构
栈:位于通用RAM(随机访问存储器),方法执行时创建方法栈帧,存放基本数据类型的变量数据和对象的引用。但对象本身不存放在栈中,而是存放在堆(new出来的对象)或者常量池中(字符串常量对象存放在常量池中)
堆:存放所有new出来的对象
静态域(方法区):存放静态成员(static定义的)
常量池(方法区):存放字符串常量、基本类型常量(public static final)
二、局部变量
2.1、基本数据类型
在方法调用时执行到该变量的初始化语句时,直接将该变量的值保存到该方法的栈帧中。
int a1 = 1;
2.2、引用类型
- 在方法调用时,将引用的堆内存中的值的地址保存到该变量到的栈内存中。
- 对于基本类型的包装类型(符合常量池区间)和String,保存在方法区的常量池。
note:变量名称存储在栈中,变量的值存储要么在常量池,要么在堆中。
Integer a2 = 1; //1存储在常量池
Integer a3 = 128; //128由于超过了常量池的范围,相当于new Integer(128), 存储在堆中
Integer a4 = 128;
String s1 = "china"; //存储在常量池
这里有个经典的面试题:String ss1 = new String("china");会创建几个对象?
答案是1-2个。如果产量池中有"china",则创建1个,否则会在堆中创建1个,常量池中创建1个。
自动拆箱装箱
这里还有个神奇的现象:
System.out.println(a1==a2); //true
System.out.println(a3==a4); //false
==比较的两边是基本数据类型和包装类型,进行值的比较(而不是比较对象地址)。
原因是:会进行自动拆箱装箱。
三、成员变量
实例成员变量:参考上面。大多数在堆内存中的值,基本数据类型有可能在常量池。
静态成员变量(类成员变量):值存在方法区的内存空间中。——方法区除了有常量池,还有静态区。