栈 堆 方法区 常量池
栈
存放java在函数中定义的基本类型的变量的引用和数据,以及对象的引用都放在栈中存储。
堆
主要存放new出来的对象和数组。
方法区
存储已经被虚拟机加载的类信息、常量、静态变量,即编译器编译后的代码等数据。
静态变量、常量在方法区;所有方法,包括静态和非静态的,也在方法区。
常量池
静态常量池
静态常量池存在于class文件中。
运行时常量池
运行时常量池,就是在class文件被加载进了内存之后,常量池保存在了方法区中,通常说的常量池值的是运行时常量池。所以呢,讨论的都是运行时常量池。
字符串常量池
String a = "abc"; String b = new String("abc"); System.out.println(a==b); 结果:false 对象b储存在堆中,这个是不用质疑的, 而a作为字面量一开始储存在了class文件中,之后运行期,转存至方法区中。 它们两个就不是同一个地方存储的。
实例
String s1 = "Hello"; String s2 = "Hello"; String s3 = "Hel" + "lo"; String s4 = "Hel" + new String("lo"); String s5 = new String("Hello"); String s6 = s5.intern(); String s7 = "H"; String s8 = "ello"; String s9 = s7 + s8; System.out.println(s1 == s2); // true; s1 和 s2 都指向了方法区常量池中的Hello。 System.out.println(s1 == s3); // true; 因为做+号的时候,会进行优化,自动生成Hello赋值给s3,所以也是true System.out.println(s1 == s4); // false; s4是分别用了常量池中的字符串和存放对象的堆中的字符串,做+的时候会进行动态调用,最后生成的仍然是一个String对象存放在堆中。 System.out.println(s1 == s9); // false; 在JAVA9中,因为用的是动态调用,所以返回的是一个新的String对象。所以s9和s4,s5这三者都不是指向同一块内存 System.out.println(s1 == s6); // true; 归功于intern方法,这个方法首先在常量池中查找是否存在一份equal相等的字符串如果有的话就返回该字符串的引用,没有的话就将它加入到字符串常量池中,所以存在于class中的常量池并非固定不变的,可以用intern方法加入新的.
特例1
public class test { public static final String a = "123"; public static final String b = "456"; public static void main(String[] args) { String c = "???"; String d = a + b; System.out.println(c = d); } } // 我们可以发现, // 对于final类型的常量它们已经在编译中被确定下来, // 自动执行了+号,把它们拼接了起来,所以就相当于执行了"123" + "456";
特例2
public class test2 { public static final String a; public static final String b; static { a = "123"; b = "456"; } public static void main(String[] args) { String c = "123456"; String d = a + b; System.out.println(c == d); } } // 上个例子是在编译期间, // 就已经确定了a和b,但是在这段代码中, // 编译期static不执行的,a和b的值是未知的, // static代码块,在初始化的时候被执行,初始化属于类加载的一部分, // 属于运行期。看看反编译的结果,很明显使用的是indy指令, // 动态调用返回String类型对象。 // 一个在堆中一个在方法区常量池中,自然是不一样的。
本文来自博客园,作者:jsqup,转载请注明原文链接:https://www.cnblogs.com/jsqup/p/16116022.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?