今天又重新学习了一下String类,看来以前学的还是不扎实啊,下面说一说吧。
下面来看一个例子:
String s1 = new String("hello");
String s2 = new String("hello");
String s31 = s2;
String s32 = new String(s2);
String s4 = "hello";
String s5 = "hello";
String s61 = s5;
System.out.println(s1.equals(s2));//true
System.out.println(s1.equals(s31));//true
System.out.println(s1.equals("hello"));//true
System.out.println();
System.out.println(s1 == s2);//false
System.out.println(s1 == s31);//false
System.out.println(s1 == "hello");//false
System.out.println();
System.out.println(s2 == s31);//true
System.out.println(s2 == s32);//false
System.out.println(s32 == "hello");//false
System.out.println();
System.out.println(s4.equals(s5));//true
System.out.println(s4.equals(s61));//true
System.out.println(s4.equals("hello"));//true
System.out.println();
System.out.println(s4 == s5);//true
System.out.println(s4 == s61);//true
System.out.println(s4 == "hello");//true
System.out.println();
StringBuffer sb1 = new StringBuffer("hello");
StringBuffer sb2 = new StringBuffer("hello");
System.out.println(sb1.equals(sb2));//false
System.out.println(sb1 == sb2);//false
“因为String太过常用,JAVA类库的设计者在实现时做了个小小的变化,即采用了享元模式,每当生成一个新内容的字符串时,他们都被添加到一 个共享池中,当第二次再次生成同样内容的字符串实例时,就共享此对象,而不是创建一个新对象,这样的做法仅仅适合于通过=符号进行的初始化”
Java中,“==”运算符用来比较两个引用以查看它们是否指向同一个内存对象。而对于String实例,运行时状态会尽可能地确保任意两个具有相同字符信息的String字面值指向同一个内部对象。此过程称为驻留(interning),但是它并不有助于每个String的比较。一个原因是垃圾收集器线程删除了驻留值,另一个原因是String所在的位置可能被一个由String构造函数创建的新实例占用。如果是这样,“==”将总是返回false。
StringBuffer的情况:
StringBuffer e = new StringBuffer("hjy");
StringBuffer f = new StringBuffer("hjy");
System.out.println( e==f );//false
System.out.println( e.equals(f));//false
StringBuffer从Object里继承了Equals(),所以仍是比较内存的,和==一样,e和f内存地址不同,所以都返回false。
Continue..........
一切从String str = new String("abc")说起...
问上面这行代码创建了几个String对象?
我刚开始很自然的觉得应该是创建了一个String对象,后来查阅资料,才发现,实际上创建了两个String对象。下面说明为什么创建了两个String对象。
首先,来了解一下Java中的字符串驻留池的概念。JVM为了提高性能,将一下两种形式的字符串放在一个称之为字符串驻留池的内存块中:
形式一:String str = "abc";
形式二:"abc"
其实,形式一和形式二都是字符串的字面常量。所以,可以这样理解,即把字符串的字面常量都放在了字符串驻留池中。对形式一来说,str其实就是引用的字符串驻留池中"abc"这个String对象。
如果有如下的两行代码:
String str1 = "abc";
String str2 = "abc";
那么,上面的两行代码创建了几个String对象?答案是一个。根据我们刚才所述,那么第一行语句将在池中创建一个String对象,第二行会先在池中寻找是否有值与"abc"相同的String对象,如果有,就直接引用,没有这在池中新建String对象。这下,就明白了为什么上面的两行语句仅仅创建了一个String对象。
然后,让我们来看一看String str = new String("abc")。我们先不讨论到底创建了几个String对象。我们在这里,比较一下这种new的方式和上面的直接赋值方式两种创建String对象的不同,直接赋值的方式是在字符串驻留池中创建对象,但new这种方式是在堆中创建对象。即,new创建的String对象是不会放入字符串驻留池中的。如果一定要把某个通过new创建的字符串对象放入驻留池,可以使用intern()方法。如String strt = str.intern(),将把str的值放在驻留池中(当然,是在驻留池原来没有这个值对应的String对象的情况下),并返回驻留池中String对象的引用。
现在,可以分析String str = new String("abc");创建了几个String对象了:)很明显,传入的"abc"字符串字面常量在驻留池中创建了一个对象,new操作符在堆中创建了一个对象,所以,一共创建了两个String对象