本文大部分内容来源于《深入JAVA虚拟机》
java笔试题中,出现频率较高的一道题:String str = new String("str");String str2 = "str";产生了几个对象?我告诉你有0个,你信么?这道题解释起来比较费劲,咱们从根源说起先。
1、虚拟机内存模型
人们常说jvm分为堆区和栈区,这是比较粗的分发,实际的情况参照上图。和本道面试题有关的区域有:虚机栈、堆区、方法区、运行时常量池。
虚拟机栈:
这就是大家常说的栈区,是线程私有的,生命周期和线程相同。虚拟机栈描述的是java方法执行的内存模型:方法执行时同时创建一个栈帧(stack frame)用于存储局部变量表、操作栈、动态链接、方法出口。方法被调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中从入栈道出栈的过程。
堆区:
此区域的唯一功能就是存放对象实例。几乎所有的对象实例都是在这里分配的。虚拟机规范中的描述:所有的对象实例和数组都要在堆上分配。但是随着JIT编译器的发展与逃逸分析技术的逐渐成熟,栈上分配、标量替换优化技术导致了一些微妙的变化,所有的对象都分配在堆上也逐渐变得不是那么“绝对”的了。
方法区:
存储已被jvm加载的类信息、常量、静态变量、即时编译器编译后的代码数据
运行时常量池:
运行时常量池(Runtime Constant Pool)是方法区的一部分
2、到底产生几个对象
看String str = new String("str"),String str这部分将反映到java栈的本地变量表中作为一个reference,而new String("str")将会在堆区分配内存,同时检查该实例的值("str")是否存在于运行时常量池,不存在则在运行时常量池创建该字串值。
再看接下来的这句String str2 = "str",String str2在栈区创建一个refrence,没有new,也就是没有对象实例在堆区分配,而在运行时常量池中存在"str",则无需创建新的值
返回来再看这两句到底创建的多少东西,在栈区2个 reference、堆区1个String的实例、方法区内运行时常量池中1个字串值"str"。很遗憾,这些东西里面没有一样是称作为“对象”的,因为在堆区的那个叫String对象的实例,所以说这两句共创建了0个对象。卧槽,0个对象是啥意思,意思就是说:出笔试题的人太挫了,基本概念都搞不懂,瞎出题,害的做题人看不懂题。
哈,开个玩笑,真的做题的时候,可别写0个对象,可是我真的不知道该回答几个