阅读建议:本博客基于《Java编程思想》、《深入理解Java虚拟机》、《java并发编程实战》三本Java书籍和面试中遇到的问题而做的总结。
JVM(JAVA Virtual Machine Java虚拟机)运行时数据区域:程序计数器、虚拟机栈(为执行Java方法服务)、本地方法栈(native方法服务)、堆(类实例)、方法区(类信息、常量、静态变量,即时编译器编译的代码),运行时常量池(用于存放编译期生成的各种字面值和符号引用典型的有String类的intern())。
线程私有的区域:程序计数器、虚拟机栈、本地方法栈。
线程共享区域:堆、方法区、运行时常量池。
一、方法区
1.static变量:
在搞清楚静态变量前,首先必须先清楚类实例和类对象的区别:类实例和类对象是不同的概念。从面向对象的角度出发,所有一切都是对象,类本身是对象的一种,类对象是个抽象的概念;类的实例就是具体类的实例对象,类实例是具体的概念;其次必须清楚编译期(类的加载过程)与运行期JVM干了哪些事。
静态变量与类实例无关,属于类对象的变量。静态变量在类加载的时候就已经初始化值了,并存放在静态存储区中,在运行期直接通过类对象调用就行;非静态变量需要new一个对象的实例,从对象实例中去获取,他是存放于堆中(对象)或者堆栈中(基本类型)。
类的静态变量只占据一个存储空间,所有对象实例都共享该对象类的静态变量,也就是说所有new出来的对象实例,通过对象实例获取的静态字段的值都是取值同一个存储空间的值。不会因为new一个对象实例而增加一块存储空间来存储静态变量,因为静态变量在类加载的过程中就已经分配存储空间了,并且一次分配后就再也不会重新分配新的存储空间了。如果你通过不同的类实例去修改静态变量的值,其他其实获取静态变量的值就是已经改变后的值。
问题1:为什么调用static静态变量不需要创建任何对象,直接通过类.静态变量直接获取?
2.final常量
二、运行常量池
1.String类型:String是final修饰的类,对象实例存在于运行时常量池或堆中。
a. 当调用 intern 方法时,如果池已经包含一个等于此 String 对象的字符串(该对象由 equals(Object) 方法确定),则返回池中的字符串。否则,将此 String 对象添加到池中,并且返回此 String 对象的引用。
b.String a = "hello world"与 String a = new String("hello world")是不同的对象,前者存储在运行时常量池,后者存放于堆中,二者存在不同的运行时数据区域中;存放在常量池中的好处是节约内存空间,String a = "hello world",如果运行时常量池里有这个字符串则句柄直接指向该字符串即可,若没有则创建该字符串并将句柄a指向该字符串。
c.字符串为何设计成final类型呢?从继承、性能、并发安全上考虑。
4.基本数据类型:存放于堆栈中,便于高效存取。
5.数组
6.对象:
结合class文件结构以及类加载(加载、验证、准备、解析、初始化、使用、卸载)过程详细叙述以上变量的初始化过程,以及变量所在JVM运行时数据结构的位置。
说明:目前仅有提纲,后续会陆续补充