String str1 = "str";
String str2 = "ing";
String str3 = "str" + "ing";//常量池中的对象
String str4 = str1 + str2; //在堆上创建的新的对象
String str5 = "string";//常量池中的对象
System.out.println(str3 == str4);//false
System.out.println(str3 == str5);//true
System.out.println(str4 == str5);//false
对于编译期可以确定值的字符串,也就是常量字符串 ,jvm 会将其存入字符串常量池。
字符串常量池 是 JVM 为了提升性能和减少内存消耗针对字符串(String 类)专门开辟的一块区域,主要目的是为了避免字符串的重复创建。
String aa = "ab"; // 放在常量池中 String bb = "ab"; // 从常量池中查找 System.out.println(aa==bb);// true
JDK1.7 之前运行时常量池逻辑包含字符串常量池存放在方法区。JDK1.7 的时候,字符串常量池被从方法区拿到了堆中。
对象引用和“+”的字符串拼接方式,实际上是通过 StringBuilder
调用 append()
方法实现的,拼接完成之后调用 toString()
得到一个 String
对象 。
String str4 = new StringBuilder().append(str1).append(str2).toString();
不过,字符串使用 final
关键字声明之后,可以让编译器当做常量来处理。
final String str1 = "str";
final String str2 = "ing";
// 下面两个表达式其实是等价的
String c = "str" + "ing";// 常量池中的对象
String d = str1 + str2; // 常量池中的对象
System.out.println(c == d);// true
只要使用 new 的方式创建对象,便需要创建新的对象 。
使用 new 的方式创建对象的方式如下,可以简单概括为 3 步:
- 在堆中创建一个字符串对象
- 检查字符串常量池中是否有和 new 的字符串值相等的字符串常量
- 如果没有的话需要在字符串常量池中也创建一个值相等的字符串常量,如果有的话,就直接返回堆中的字符串实例对象地址。
因此,str2
和 str3
都是在堆中新创建的对象。
4.2 String s1 = new String("abc");这句话创建了几个字符串对象?
会创建 1 或 2 个字符串:
- 如果字符串常量池中已存在字符串常量“abc”,则只会在堆空间创建一个字符串常量“abc”。
- 如果字符串常量池中没有字符串常量“abc”,那么它将首先在字符串常量池中创建,然后在堆空间中创建,因此将创建总共 2 个字符串对象.
4.3 8 种基本类型的包装类和常量池
Java 基本类型的包装类的大部分都实现了常量池技术。
Byte
,Short
,Integer
,Long
这 4 种包装类默认创建了数值 [-128,127] 的相应类型的缓存数据,Character
创建了数值在 [0,127] 范围的缓存数据,Boolean
直接返回 True
Or False
。
Integer i1 = 40;
Integer i2 = new Integer(40);
System.out.println(i1==i2);
Integer i1=40
这一行代码会发生装箱,也就是说这行代码等价于 Integer i1=Integer.valueOf(40)
。因此,i1
直接使用的是常量池中的对象。而Integer i2 = new Integer(40)
会直接创建新的对象。
因此,答案是 false
。你答对了吗?
记住:所有整型包装类对象之间值的比较,全部使用 equals 方法比较
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);// true
System.out.println(i1 == i2 + i3);//true
System.out.println(i1 == i4);// false
System.out.println(i4 == i5);// false
System.out.println(i4 == i5 + i6);// true
System.out.println(40 == i5 + i6);// true
关于i4 == i5 + i6;
左边对象 == 对象 + 对象
但是 i5 + i6在运算的时候会自动拆箱;所以就变为了数值 40 + 数值 0;结果为数值40;
左边对象 == 数值40;对象和数值不能直接比较,所以需要对左边的对象i4进行自动拆箱;
左边对象i4拆箱为数值40;最终结果为:40 == 40;返回true;
关于 i1 == 14;左边对象;右边对象,两边都是对象可以直接进行比较;因为用==比较的时候比较的是地址值;所以返回false;