public final class String implements java.io.Serializable, Comparable<String>, CharSequence {
privatefinalchar value[];
privateint hash; }
String其实是对一个char数组的封装。提供了各种操作方法。值得注意的是这个数组的final的,也就是这个引用是不可变的。注意是引用,数组中每一项的值理论上是可以改变的,比如通过反射,但是不推荐这么做。
关于String有一些有趣的地方:
package terry.java.base;
publicclass StringTest {
publicstaticvoid main(String[] args) {
String a = "hello";
String b = "hello";
String newA = new String("hello");
String newB = new String("hello");
System.out.println("****** Testing Object == ******");
System.out.println("a==b ? :" + (a==b));
System.out.println("newA==newB ? :" +(newA==newB));
System.out.println("a==newA ? :" + (a==newA));
System.out.println("***** Testing String Object intern method******");
System.out.println("a.intern()==b.intern() ? : " + (a.intern()==b.intern()));
System.out.println("newA.intern()==newB.intern() ? :" + (newA.intern()==newB.intern()));
System.out.println("a.intern()==newA.intern() ? :" + (a.intern()==newA.intern()));
System.out.println("a=a.intern() ? :" + (a==a.intern()));
System.out.println("newA==newA.intern() ? : " + (newA==newA.intern()));
System.out.println("****** Testing String Object equals method******");
System.out.println("equals() method :" + a.equals(newA));
String c = "hel";
String d = "lo";
final String finalc = "hel";
final String finalgetc = getc();
System.out.println("****** Testing Object splice ******");2 System.out.println("a==\"hel\"+\"lo\" ? :" + (a=="hel"+"lo"));
System.out.println("a==c+d ? : " + (a==c+d));
System.out.println("a==c+\"lo\" ? : " + (a==c+"lo"));
System.out.println("a==finalc+\"lo\" ? :" + (a==finalc+"lo"));
System.out.println("a==finalgetc+\"lo\" ? :" + (a==finalgetc+"lo"));
}
privatestatic String getc(){
return"hel";
}
}
输出:
****** Testing Object == ******
a==b ? :true
newA==newB ? :false
a==newA ? :false
***** Testing String Object intern method******
a.intern()==b.intern() ? : true
newA.intern()==newB.intern() ? :true
a.intern()==newA.intern() ? :true
a==a.intern() ? :true
newA==newA.intern() ? : false
****** Testing String Object equals method******
equals() method :true
****** Testing Object splice******
a=="hel"+"lo" ? :true
a==c+d ? : false
a==c+"lo" ? : false
a==finalc+"lo" ? :true
a==finalgetc+"lo" ? :false
而String newA = new String("hello")这种方方式,会在堆内存中新建一个字符串对象,所以与a、b所指向的常量池中对象是不同对象。==为false。
接下来出现了一个不太常用的intern方法。这个方法的作用是,在常量池中查找是否有与当前字符串值相同的常量,如果没有,则新建常量并返回常量引用,但当前引用不变;如果有直接返回引用。所以上例中newA.intern()返回了常量池中”hello“的引用与a、b为相同对象,但newA在intern后仍指向对中的那个对象,所以newA==newA.intern()不成立。这个方法对于重复率高的字符串可以提高内存利用率,减轻内存负担。但是常量表中的对象,一般不会被回收,会随着堆积占用越来越多的内存。所以要根据实际情况权衡利弊。
再往下,Java中罕见的运算符重载,是+和+=对String的重载,在使用中也有些需要注意的地方。类似"a" + "b"这样字符串常量用+连接的情形,在编译期间,JVM就将+连接优化为连接后的值。同时fianl修饰的已赋值String变量,在编译期同样被一个常量,保存到常量池中。所以上面输出中的14/17行的结果就不足为奇了。
在15行的结果中,JVM对于变量间的+操作,是转换为StringBuilder的append操作,所以产生了新的堆内对象。所以为false。
第18行的结果,你能给出原因么?