再谈String对象前我们先看段经典代码
public class TestString {
public static void main(String[] args) {
String a = "hello";
String b = "hello";
String c = new String("hello");
System.out.println(a==b);
System.out.println(a==c);
System.out.println(b==c);
System.out.println(a.equals(c));
}
}
输出结果
上述代码中我定义了3个String引用分别是a,b,c;并且都设置了相同的值"hello"字符串。
为什么在比较的时候会有不一样的结果?
首先
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[];
/** Cache the hash code for the string */
private int hash; // Default to 0
在String类的源码中String类是被final修饰的,这表示String类是不可变的。
一旦生成不可修改。
这样设计应该是为了线程安全和资源利用率考虑。
String a = “hello”;
这样写其实是定义了一个字符串常量。java虚拟机对字符串常量有一个特殊的位置存储–常量池
String b = “hello”;
当在创建b引用的时候,虚拟机会先去常量池中寻找有没有现成的常量可以用的。有的话就直接返回常量的引用地址,所以这里b直接直接指向了a创建的常量。
String c = new String(“hello”);
这样写会在jvm的堆内存中创建一个新的对象。
c引用指向这个新对象的地址。
然后我们来看比较的结果:
第一次比较:我们比的是两个引用的地址。根据上述分析,显然它两的地址是一样的。所以结果是true。
第二次比较:a指向的是常量池中的内存;c指向是堆中的内存。所以是false。
第三次同上。
第四次比较:返回的结果是true。说明这个equals不是用来比较地址的。而Object中的equals方法是用来比较两个内存地址的,说明String中的equals方法被重写了,用来比较值了。只要值一样就返回true。而这正式我们业务中常用的。
StringBuffer和StringBuilder的区别:
1.StringBuffer的效率低,但是线程安全;StringBuilder的效率更高但是线程不安全。
2.它两都是可变字符串,String不是。