1、String str = new String("abc") 创建了几个字符串对象?
答案:1个或者2个
Ⅰ 如果字符串常量池中已经有"abc"存在,这种情况只需要新建 1 个对象,即 new 一个对象放在堆中。
Ⅱ 当字符串常量池中没有 "abc",此时会创建如下 2 个对象:
一个是字符串字变量 "abc" 所对应的、驻留(intern)在字符串常量池中的实例,字符串常量池只存放实例对象的引用。
另一个是通过 new String() 创建并初始化的,内容与"abc"相同的实例,在堆中。
总结: new String("xxx"); 如果字符串常量池intern中没有对应的xxx 那么就需要在字符串常量池新建,然后再在堆上new 一个对象。
2、String str1 = “abc” 和 String str2 = new String(“abc”)的区别?
两者看似都是创建了一个字符串对象,但在内存中却是不一样的:
String str1= “abc” 在编译期,JVM 会去字符串常量池来查找是否存在“abc”,如果不存在,就在字符串常量池中开辟一个空间来存储“abc”;如果存在,就不用新开辟空间。然后在栈内存中开辟一个名字为 str1 的空间,来存储 “abc” 在常量池中的地址值。
String str2 = new String("abc")在编译阶段 JVM 先去字符串常量池中查找是否存在 “abc”,如果过不存在,则在常量池中开辟一个空间存储 “abc”。在运行时期,通过 String 类的构造器在堆内存中 new 了一个空间,然后字符串常量池中的 “abc”复制一份存放到堆空间中,在栈中为 str2 开辟空间,存放堆中 new 出来的这个 String 对象的地址值。
也就是说,前者在初始化的时候可能创建了一个对象,也可能一个对象也没有创建;后者因为 new 关键字,至少在内存中创建了一个对象,也有可能是两个对象。
3、Java中的128陷阱?
先来看一个例子:
public static void main(String[] args) { Integer a=127,b=127; Integer c=128,d=128; System.out.println(a==b);// true System.out.println(c==d);// false }
为什么出现这种情况呢?
我们都知道Integer 是 基本类型int 的包装类型。
在Java设计之初,设计者认为,开发者可能经常用到的数字范围都在100以内,而每次使用这些数字的包装类型都要开辟新空间的话,可能会占用大量的资源。
因此他们规定在-128~127之间的Integer类型的变量,直接指向常量池中的缓存地址,不再使用new去开辟出新的空间。
执行 Integer c = 128,相当于执行:Integer c = Integer.valueOf(128),基本类型自动转换为包装类的过程称为,自动装箱(autoboxing)。
这也是出现上述代码两次比较结果不同的原因!下面我们看下valueOf() 源码去体会下:
public static Integer valueOf(int i) { if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); }
在Integer 中引入了IntegerCache 来缓存一定范围的值,默认情况下范围为:-128~127。
因此:上述代码中的 127 命中了 IntegerCache,所以 a 和 b 是相同对象,而 128 则没有命中,所以 c 和 d 是不同对象。
那么,如果想要正确比较的话c与d的话,就需要拆箱比较,即在变量后加intValue()方法:
public static void main(String[] args) { Integer a=127,b=127; Integer c=128,d=128; System.out.println(a==b);// true System.out.println(c.intValue()==d.intValue());// true }
可以直接记住下面的表格,道理都是一样的: