前言
本次代码使用 jdk 1.8版本,并且以下代码示例除了第一个写了main()方法,并且所有的示例分别独立运行 ,其余为了简洁做了缺省main()。在创建字符串分析的同时,都默认省略了栈中的句柄指向分析。进入正题之时,先科普几个知识点
- String源码里面标注为final修饰的类,是一个不可改变的对象,那平时用到字符串A+字符串B怎么改变了呢,其实这里有涉及到String的常量池,首先常量池存放在方法区。
- 在jdk1.6时,方法区是存放在永久代(java堆的一部分,例如新生代,老年代)而在jdk1.7以后将字符串常量池移动到了的堆内存中
- 在jdk1.8时,HotspotVM正式宣告了移除永久代,取而代之的是元数据区,元数据区存放在内存里面(存放一些加载class的信息),但是常量池还是和jdk1.7存放位置一样还是存放在堆中。
一、常见的面试题
public static void main(String[] args){
String s1 = new String("123");
String s2 = "123";
System.out.println(s1 == s2);
}
基本上大家都能知道是false,但是再这么深究一次,问 String s1 = new String(“123”) 创建了几个对象,String s2 = “123” 创建 了几个对象,那如果题目稍微改变一下成下面这样,那输出的又是什么?
String s1 = new String("123").intern();
String s2 = "123";
System.out.println(s1 == s2); // true
// 如果这样再改一下
String s1 = new String("123");
s1.intern();
String s2 = "123";
System.out.println(s1 == s2); // false
如果对输出结果不是很明白的,本文都会一一解答并且进行拓展。
一、创建字符串分析:
首先要分析String,一定要知道String几种常见的创建字符串的方式,以及每一种不同的方式常量池和堆分别是什么储存情况。
1.直接写双引号常量来创建
判断这个常量是否存在于常量池,
如果存在,则直接返回地址值(只不过地址值分为两种情况,1是堆中的引用,2是本身常量池的地址)
如果是引用,返回引用地址指向的堆空间对象地址值
如果是常量,则直接返回常量池常量的地址值,
如果不存在,
在常量池中创建该常量,并返回此常量的地址值
String s = "123";
//true,因为s已经在常量池里面了,s.intern()返回的也是常量池的地址,两者地址一样为true
System.out.println(s == s.intern());
转自:https://blog.csdn.net/xzjayx/article/details/103020029?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-3.control&dist_request_id=9e66ef09-8558-4e27-8909-50f68c0d45e9&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-3.control