String 类是 final 类, 它内部的方法也默认被 final 修饰, 不能重写.
字符串常量池
当这样声明一个字符串
String str = “hello java”;
JVM 会检测字符串常量池中是否存在这个值的字符串, 如果存在, 就直接赋值给 str, 否则创建一个新的, 再赋值给 str. 当连续用同样的方式声明两个字符串并作比较
String str1 = “hellojava”;
String str2 = “hellojava”;
boolean flag = str1==str2;//true
结果为 true. 当我们这样声明
String str1 = “hello”;
String str2 = “java”;
String str3 = “hellojava”;
String str4 = str1+str2;
boolean flag = str3==str4;//false
结果为 false. 这是因为 str4 是有两个引用类型结合而成, 它的值在编译期无法确定. 如果将 str1 和 str2 声明为 final 类型
final String str1 = “hello”;
final String str2 = “java”;
String str3 = “hellojava”;
String str4 = str1+str2;
boolean flag = str3==str4;//true
str1 和 str2 都是被 final 修饰的字符串常量, 那么 str4 在编译期就可以被确定. 因此结果是 true.
通过 new 创建字符串
String str3 = “hellojava”;
String str4 = new String(“hellojava”);
boolean flag = str3==str4;//false
这是因为 new 会在堆中创建一个 hellojava 的实例对象, 并用栈中的 str4 指向它. 而 str3 指向的是方法区中字符串常量池中的 hellojava. 当然堆中的 hellojava 指向的也是字符串常量池中的 hellojava(如果存在的话). 要了解一下 str3 和 str4 的声明做了什么?
先声明 str3. 会在方法区的字符串常量池中直接创建一个字符串 ”hellojava”, 使 str3 指向它. 紧接着用 new 创建 str4 时, 会先查找字符串常量池中是否包含字符串 ”hellojava”. 如果有直接返回, 没有就在常量池中创建. 然后在堆中创建实例对象, 并将这个实例对象指向常量池中的字符串 ”hellojava”, 然后将实例对象赋给栈中的 str4.