public class StringCompare {
public static void main(String[] args) {
String s1 = "Hello";
String s2 = "Hello";
String s3 = "Hel" + "lo";
String s4 = "Hel" + new String("lo");
String s5 = new String("Hello");
String s6 = s5.intern();
String s7 = "H";
String s8 = "ello";
String s9 = s7 + s8;
final String a = "H";
final String b = "ello";
String s10 = a + b;
// == 与 equals方法都是比较地址,如果重写了equals方法,则比较的是内容,
//String重写了equals方法
// JVM会首先去常量池中查找是否有”Hello”这个字符串常量,有的话就返回引用地址给s1,
// 没有就将”Hello”字符串常量放入常量池,再返回地址给s1,s2也是”Hello”字符串常量,
// 因此JVM会将常量池中的该字符串引用地址返回给s2,
//因此实际上s1和s2指向的是同一个字符串字面量
// 所以才会为true。
System.out.println(s1 == s2); // true
//”Hel“与”lo“都在堆中,常量相加的时候,其实是在编译期就直接相加为“Hello”,
//这是JVM的优化,不会创建 StringBuilder 对象
// 所以运行的时候,s1和s3的字节码是一样的。因为在常量池中有了一个“helloword”,
// 所以两个引用指向的是一个字符串“helloword”,所以返回结果也是true。
System.out.println(s1 == s3); // true
//!动态调用,创建StringBuffer对象,然后调用append方法,返回的都是String对象
// s4是分别用了常量池中的字符串和存放对象的堆中的字符串,
//其实是创建了一个StringBuffer对象,
//然后用StringBuffer对象执行append方法来创建出字符串对象“Hello”,然后再转换成为String。
// 做+的时候会进行动态调用,最后生成的仍然是一个String对象存放在堆中。
System.out.println(s1 == s4); // false
//进行了动态调用,这个转换后的是个String对象,也就是s9是放在堆里面的。
//而s1则是字符串常量,放在常量池里面。
// 所以返回的是false。
System.out.println(s1 == s9); // false
//s4与s5都是不同的String对象,所以地址不同
System.out.println(s4 == s5); // false
//为啥s1 和 s6地址相等呢? 归功于intern方法,
// 这个方法首先在常量池中查找是否存在一份equal(内容)相等的字符串,
//如果有的话就返回该字符串的引用,
// 没有的话就将它加入到字符串常量池中,
// 所以存在于class中的常量池并非固定不变的,可以用intern方法加入新的
System.out.println(s1 == s6); // true
//当final变量是基本数据类型以及String类型时,如果在编译期能知道它的确切值,
//则编译器会把它当做编译期常量使用。
// 也就是说在用到该final变量的地方,相当于直接访问的这个常量,不需要在运行期确定。
System.out.println(s1 == s10); // true
}
}