1.只要使用 new 方法,便需要创建新的对象,创建两个对象,一个在堆中,一个在常量池中(若常量池中已存在该对象,则不再创建),这是两个不同的对象,指向堆中的和指向常量池中的不同.
String str2 = new String("cc");
当new String("cc")后,堆中创建了"cc",也会在常量池创建"cc",创建了2个字符串对象!
2.直接使用双引号声明出来的 String 对象会直接存储在常量池中
3.如果不是用双引号声明的 String 对象,可以使用 String 提供的 intern 方法。String.intern() 是一个 Native 方法,它的作用(在JDK1.6和1.7操作不同)是:如果运行时常量池中已经包含一个等于此 String 对象内容的字符串,则返回常量池中该字符串的引用;如果没有,在jdk1.6中,将此String对象添加到常量池中,然后返回这个String对象的引用(此时引用的串在常量池)。在jdk1.7中,放入一个引用,指向堆中的String对象的地址,返回这个引用地址(此时引用的串在堆)
4.常量字符串的“+”操作,编译阶段直接会合成为一个字符串。
如string str=”JA”+”VA”
常量池中,创建"JA"和"VA",连接过程编译器直接优化成"JAVA"(在编译阶段会直接合并成语句String str=”JAVA”),会去常量池中查找是否存在”JAVA”,如果没有,则在常量池中进行创建,如果有,则直接返回常量池中"JAVA"的引用
5.对于final字段,编译期直接进行了常量替换(而对于非final字段则是在运行期进行赋值处理的)。
final String str1=”ja”;
final String str2=”va”;
String str3=str1+str2;
在编译时,直接替换成了String str3=”ja”+”va”,根据第4条规则,再次替换成String str3=”JAVA”
6.常量字符串和变量拼接时(如:String str3=baseStr + “01”;)会调用stringBuilder.append()在堆上创建新的对象(此时并不会在常量池中创建对应的对象,只在堆中创建对象)。
Integer对象详解(摘自他人):
- Integer i1=40;Java 在编译的时候会直接将代码封装成 Integer i1=Integer.valueOf(40); 从而使用常量池(-128,127)中的对象。
- Integer i1 = new Integer(40) ;这种情况下会创建新的对象。
- flocat,double没有实现常量池技术,其他包装类都实现常量池技术
Integer 比较(==)更丰富的一个例子:
Integer i1 = 40; Integer i2 = 40; Integer i3 = 0; Integer i4 = new Integer(40); Integer i5 = new Integer(40); Integer i6 = new Integer(0); System.out.println("i1=i2 " + (i1 == i2)); System.out.println("i1=i2+i3 " + (i1 == i2 + i3)); System.out.println("i1=i4 " + (i1 == i4)); System.out.println("i4=i5 " + (i4 == i5)); System.out.println("i4=i5+i6 " + (i4 == i5 + i6)); System.out.println("40=i5+i6 " + (40 == i5 + i6)); 结果:
i1=i2 true
i1=i2+i3 true
i1=i4 false
i4=i5 false
i4=i5+i6 true
40=i5+i6 true
解释:
语句 i4 == i5 + i6,因为 + 这个操作符不适用于 Integer 对象,首先 i5 和 i6 进行自动拆箱操作,进行数值相加,即 i4 == 40。然后Integer对象无法与数值进行直接比较,所以i4自动拆箱转为int值40,最终这条语句转为40 == 40进行数值比较。