最近在阅读《深入理解Jav虚拟机》的运行时常量池章节,看到”java语言并不要求常量池一定只有编译器才能产生…运行期间也可以将新的常量放入常量池,这种特性被开发人员利用得比较多的时String类的intern()方法。”于是我便去深入了解了一下。
1 public static void main(String[] args) {
2 String a="王者";
3 String b="荣耀";
4 String c=a+b; //编译期常量池不存在"王者荣耀"
5 String d=c.intern();
6 System.out.println(d==c);
7 }
上面为什么是true呢,接下来讲述intern()
JDK1.7后,intern方法先去查询常量池中是否有已经存在,如果存在,则返回常量池中的引用,当字符串常量池中找不到对应的字符串时,而只是生成一个对该字符串的引用在字符串常量池。所以”王者荣耀”本身不会在字符串常量池
前面说了intern可以在程序运行时将新的常量放入运行时常量池,接下来就开始演示intern的强大用处
public static void main(String[] args) throws Exception {
long start=System.currentTimeMillis(); //获取开始时间
String[] arr = new String[10000000];
Integer[] a= new Integer[10000000];
for (int i = 0; i < 10000000; i++) {
a[i] = (int)(1+Math.random()*(3));
}
for (int i = 0; i < 10000000; i++) {
arr[i] = new String(String.valueOf(a[i]));
}
long end=System.currentTimeMillis(); //获取结束时间
System.out.println("程序运行时间: "+(end-start)+"ms");
}
//程序运行时间: 14461ms
public static void main(String[] args) throws Exception {
long start=System.currentTimeMillis(); //获取开始时间
String[] arr = new String[10000000];
Integer[] a= new Integer[10000000];
for (int i = 0; i < 10000000; i++) {
a[i] = (int)(1+Math.random()*(3));
}
for (int i = 0; i < 10000000; i++) {
arr[i] = new String(String.valueOf(a[i])).intern();
}
long end=System.currentTimeMillis(); //获取结束时间
System.out.println("程序运行时间: "+(end-start)+"ms");
}
//程序运行时间: 1688ms
就是有无调用intern方法,但程序运行时间差了10倍!
我们明确的知道,会有很多重复的相同的字符串产生,但是这些字符串的值都是只有在运行期才能确定的。所以,我们通过intern显示的将其加入运行时常量池
因为随机数是运行期才知道的,假设整个过程只产生”1″,”2″,”3″的字符串,调用了intern()就会把的堆内对象索引放入了运行常量池,下次在看见”1″,”2″,”3″,返回第一次在堆中String的对象地址,不用创建新对象,使用intern()在堆中只会创建6个对象(堆+方法区),而不使用intern则创建100000000个对象,并且常量池里并没有”1″,”2″,”3″
当在编译期知道确定了字面量,new String(“王者荣耀”).intern()没什么意义的,直接就返回了运行时字符串的地址,但intern()并不是这样的初衷,而是为了解决运行时才出现的常量,不是解决编译时在字符串常量池的问题
public class RuntimeConstantPoolOOM {
public static void main(String[] args) {
String str1 = new StringBuilder("计算机").append("软件").toString();
System.out.println(str1.intern() == str1);
//true
String str2 = new StringBuilder("ja").append("va").toString();
System.out.println(str2.intern() == str2);
//flase
}
}
最好测试字符串采取选用中文,书中有所描述,防止类加载时,默认加载类加载了字符串导致常量池中以存在真正的字面量
技术有限,如有错误,请指正,谢谢
Original: https://www.cnblogs.com/Dear-John/p/15935714.html
Author: 今晚螃蟹下酒
Title: 为什么要使用String.intern()
原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/715211/
转载文章受原作者版权保护。转载请注明原作者出处!