为什么要使用String.intern()
最近在阅读《深入理解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 } }
最好测试字符串采取选用中文,书中有所描述,防止类加载时,默认加载类加载了字符串导致常量池中以存在真正的字面量
技术有限,如有错误,请指正,谢谢

浙公网安备 33010602011771号