面试题答案
一键面试Java字符串常量池在内存中的位置
- JDK 1.6及之前:字符串常量池位于方法区(永久代)中。方法区是各个线程共享的内存区域,用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
- JDK 1.7及之后:字符串常量池被移到了堆内存中。堆是Java虚拟机所管理的内存中最大的一块,是被所有线程共享的一块内存区域,几乎所有的对象实例以及数组都在这里分配内存。
字符串常量池与堆内存的交互
- 常量池引用堆对象:当在代码中使用字符串字面量时,如
String str = "hello";
,首先会检查字符串常量池中是否已经存在 "hello" 这个字符串对象。如果存在,则直接返回常量池中该字符串对象的引用;如果不存在,则在堆内存中创建该字符串对象,并将其引用放入字符串常量池中。 - 字符串操作影响交互:对于字符串的拼接操作,如果拼接结果是编译期可知的常量,如
String s1 = "a" + "b";
,在编译时就会直接拼接为 "ab",并在常量池中查找或创建该字符串对象。如果拼接操作涉及变量,如String a = "a"; String s2 = a + "b";
,在运行时会在堆中创建新的字符串对象,然后根据情况决定是否将其引用放入常量池(例如调用intern()
方法)。
使用字面量方式创建字符串和通过 new
关键字创建字符串在内存中的分配区别
- 字面量方式创建:例如
String str1 = "hello";
- 首先检查字符串常量池中是否存在 "hello" 这个字符串对象。
- 如果存在,直接返回常量池中该字符串对象的引用,此时堆内存中不会新创建对象(除非常量池中该对象尚未创建)。
- 如果不存在,在堆内存中创建该字符串对象,并将其引用放入字符串常量池,然后返回该引用。
- 通过
new
关键字创建:例如String str2 = new String("hello");
- 无论字符串常量池中是否存在 "hello",都会在堆内存中创建一个新的
String
对象。 - 同时,如果常量池中不存在 "hello",还会在常量池中创建一个 "hello" 字符串对象(这里创建的对象是共享的,后续使用字面量 "hello" 会直接引用常量池中的这个对象)。而
new
创建的对象与常量池中的对象是不同的对象,只是内容相同。可以通过调用intern()
方法将new
创建的字符串对象的引用加入到常量池中,如果常量池中已存在相同内容的字符串,则返回常量池中的引用。
- 无论字符串常量池中是否存在 "hello",都会在堆内存中创建一个新的