Java String intern() 解析

String 在 java 中是一个使用最频繁的类,也是占据内存最大的类,合理的优化 String 对象,可以节省宝贵的内存资源。

String#intern()

在每次赋值的时候使用,如果常量池中有相同值,就会重复使用该对象,返回对象引用,这样一开始的对象就可以被回收掉。

例子

上一段代码

String s1 = "abc";
String s2 = new String("abc");
String s3 = s2.intern();

System.out.println("1:" + (s1 == s2));
System.out.println("2:" + (s2 == s3));
System.out.println("3:" + (s1 == s3));
System.out.println("================================");
String s4 = new String("1") + new String("1");
String s5 = "11";
System.out.println("4:" + (s4 == s5));
String s6 = s4.intern();
System.out.println("5:" + (s4 == s5));
System.out.println("6:" + (s5 == s6));
System.out.println("7:" + (s4 == s6));

结果是:

1:false
2:false
3:true
================================
4:false
5:false
6:true
7:false

解析

理解这一块的核心在于这段代码运行是分为2个阶段的,1.类加载 2.类执行

1.类加载时(注:JDK 1.7 之后,常量池合并在堆中):

  • 字符串常量:在常量池中开辟一个空间,存放字符串对象
  • 字符串变量:会把new String() 中的字符串放入常量池中

2.类运行时:在堆内存中开辟一个空间存放该对象,String 类中的 char 数组引用常量池对象,返回堆内存中的地址给变量引用。

如果调用 intern() 方法,就会去字符串常量池中查看是否有等于该对象字符串的引用,如果有,就返回返回字符串常量池中的引用

额外注意 s4 动态生成的字符串
动态生成的字符串直接在堆上创建,字符串常量池没有,当调用 intern 方法获取引用时,则会去常量池中判断是否有相等的引用,如果有返回引用,如果没有则放入。

intern 方法 不改版本身的指针引用,从7就可以看出,s4调用intern 后与 s6 比较,仍不相等。

总结

  • 非动态生成的字符串,在类加载时就已经将字符串对象放入常量池中,运行时视对象是常量还是变量赋值:

    • 常量:直接执行常量池
    • 变量:先指向堆开辟的new 空间,堆再指向常量池
  • 动态生成的字符串,直接在堆上创建,调用 intern 方法时,会去常量池中判断,如果有返回地址,如果没有,放入,返回。

intern 方法,如果常量池中没有匹配的字符串,就将自己放入然后返回,否则返回字符串对象在常量池中的地址。

思考

为什么相等 ?

String a =new String("abc").intern();
String b = new String("abc").intern(); 
if(a==b) { System.out.print("a==b");}
阅读 190

推荐阅读

0 人关注
17 篇文章
专栏主页