首先让咱们了解几个概念:线程
栈 :由JVM分配区域,用于保存线程执行的动做和数据引用。对象
堆 :由JVM分配的,用于存储对象等数据的区域。内存
常量池constant pool :在堆中分配出来的一块存储区域,用于存储显式 的String,float或者integer.这是一个特殊的共享区域,能够在内存中共享的不常常改变的东西,均可以放在这里。字符串
进入正题:原理
String a = "abc";①
String b = "abc";②引用
使用String a = "abc";的方式,能够在必定程度上提升程序的运行速度,由于JVM会自动根据栈中数据的实际状况来决定是否有必要建立新对象。
①代码执行后在Constant Pool中建立了一个值为abc的String对象,②执行时,由于Constant Pool中存在"abc"因此就不在建立新的String对象了。float
String c = new String("xyz");①
String d = new String("xyz");②程序
让咱们来看看这两句代码在内存中发生了什么,①Class被CLassLoader加载时,你的"xyz"被做为常量读入,在constant pool里建立了一个共享的"xyz",而后当调用到new String("xyz")的时候,会在heap里建立这个new String("xyz");②因为constant pool中存在"xyz"因此再也不建立"xyz",而后建立新的new String("xyz")。
对于String c = new String("xyz");的代码,与String a = "abc"不一样的是一律在堆中建立新对象,无论其字符串值是否相等,是否有必要建立新对象,从而加剧了程序的负担。
程序1
String s1 = new String("xyz"); //建立二个对象,一个引用
String s2 = new String("xyz"); //建立一个对象,而且之后每执行一次建立一个对象,一个引用
程序2
String s3 = "xyz"; //建立一个对象,一个引用
String s4 = "xyz"; //不建立对象,只是建立一个新的引用方法
重要的是理解constant pool与new关键字数据
当调用 intern 方法时,若是池已经包含一个等于此 String 对象的字符串(该对象由 equals(Object) 方法肯定),则返回池中的字符串。不然,将此 String 对象添加到池中,而且返回此 String 对象的引用。(不管怎样都返回池中的对象)
下面的这个例子能帮助咱们更深刻的理解String的存储和赋值原理
String str1 = new String("123");
String str2 = "123";
String str3 = str1.intern();
System.out.println((str1 == str2) +","+ (str3 == str2));
输出 false,true
String str4 = new String("234");
String str5 = new String("234");
String str6 = str4.intern();
String str7 = str5.intern();
System.out.println((str4 == str5) +","+ (str6 == str7));
输出 false,true