String 在 java 中是一个使用最频繁的类,也是占据内存最大的类,合理的优化 String 对象,可以节省宝贵的内存资源。
在每次赋值的时候使用,如果常量池中有相同值,就会重复使用该对象,返回对象引用,这样一开始的对象就可以被回收掉。
上一段代码
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 之后,常量池合并在堆中):
2.类运行时:在堆内存中开辟一个空间存放该对象,String 类中的 char 数组引用常量池对象,返回堆内存中的地址给变量引用。
如果调用 intern() 方法,就会去字符串常量池中查看是否有等于该对象字符串的引用,如果有,就返回返回字符串 常量池中的引用
。
额外注意 s4 动态生成的字符串
动态生成的字符串直接在堆上创建,字符串常量池没有,当调用 intern 方法获取引用时,则会去常量池中判断是否有相等的引用,如果有返回引用,如果没有则放入。
intern 方法 不改版本身的指针引用
,从7就可以看出,s4调用intern 后与 s6 比较,仍不相等。
非动态生成的字符串,在类加载时就已经将字符串对象放入常量池中,运行时视对象是常量还是变量赋值:
intern 方法,如果常量池中没有匹配的字符串,就将自己放入然后返回,否则返回字符串对象在常量池中的地址。
为什么相等 ?
String a =new String("abc").intern(); String b = new String("abc").intern(); if(a==b) { System.out.print("a==b");}