2. 千变万化的 String
再稍微改动一下程序,会有更奇怪的发现:
public class TestString {
public static void main(String[] args) {
String s1 = "Monday";
String s2 = new String("Monday");
if (s1 == s2)
System.out.println("s1 == s2");
else
System.out.println("s1 != s2");
if (s1.equals(s2))
System.out.println("s1 equals s2");
else
System.out.println("s1 not equals s");
}
}
我们将 s2 用 new 操作符创建
程序输出:
s1 != s2
s1 equals s2
嗯,很明显嘛
s1 s2分别引用了两个"Monday"String对象
可是为什么两段程序不一样呢?
3. 在 String 的游泳池中游泳
原来,程序在运行的时候会创建一个字符串缓冲池,当使用 s2 = "Monday" 这样的表达是创建字符串的时候,程序首先会在这个String缓冲池中寻找相同值的对象,在第一个程序中,s1先被放到了池中,所以在s2被创建的时候,程序找到了具有相同值的 s1,将 s2 引用 s1 所引用的对象"Monday" ,第二段程序中,使用了 new 操作符,他明白的告诉程序: “我要一个新的!不要旧的!”与是一个新的"Monday"Sting对象被创建在内存中。他们的值相同,但是位置不同,一个在池中游泳,一个在岸边休息。哎呀,真是资源浪费,明明是一样的非要分开做什么呢?
4. 继续潜水
再次更改程序:
public class TestString {
public static void main(String[] args) {
String s1 = "Monday";
String s2 = new String("Monday");
s2 = s2.intern();
if (s1 == s2)
System.out.println("s1 == s2");
else
System.out.println("s1 != s2");
if (s1.equals(s2))
System.out.println("s1 equals s2");
else
System.out.println("s1 not equals s2");
}
}
这次加入:s2 = s2.intern();
哇!程序输出:
s1 == s2
s1 equals s2
原来,程序新建了 s2 之后,又用intern()把他打翻在了池里
哈哈,这次 s2 和 s1 有引用了同样的对象了,我们成功的减少了内存的占用
5. == 与 equals() 的争斗
String 是个对象,要对比两个不同的String对象的值是否相同,明显的要用到 equals() 这个方法,可是如果程序里面有那么多的String对象,有那么多次的要用到 equals ,哦,天哪,真慢啊
更好的办法:
把所有的String都intern()到缓冲池去吧,最好在用到new的时候就进行这个操作
String s2 = new String("Monday").intern();
嗯,大家都在水池里泡着了吗?哈哈
现在我可以无所顾忌的用 == 来比较 String 对象的值了
真是爽啊,又快又方便!
1. 回顾一下坏脾气的 String 老弟
例程1:
class Str {
public static void main(String[] args) {
String s = "Hi!";
if (s == t)
System.out.println("equals");
else
System.out.println("not equals");
}
}
程序输出什么呢?
程序输出:equals
2. 哦,天哪,它又在搅混水了
例程2:
class Str {
public static void main(String[] args) {
String s = "HELLO";
String t = s.toUpperCase();
if (s == t)
System.out.println("equals");
else
System.out.println("not equals");
}
}
那么这个程序有输出什么呢?
慎重!再慎重!不要被 String 这个迷乱的家伙所迷惑!
它输出:equals
把程序简单的更改一下:
class Str2 {
public static void main(String[] args) {
String s = "Hello";
String t = s.toUpperCase();
if (s == t)
System.out.println("equals");
else
System.out.println("not equals");
}
}
你可能会说:不是样吗?
不!千真万确的,不一样!这一次输出:not equals
3. 你了解你的马吗?
“要驯服脱缰的野马,就要了解它的秉性”牛仔们说道。
你了解 String 吗?
解读 String 的 API ,可以看到:
toUpperCase() 和 toLowerCase() 方法返回一个新的String对象, 它将原字符串表示字符串的大写或小写形势; 但是要注意:如果原字符串本身就是大写形式或小写形式,那么返回原始对象。
这就是为什么第二个程序中 s 和 t 纠缠不清的缘故
对待这个淘气的、屡教不改的 String ,似乎没有更好的办法了
让我们解剖它,看看它到底有什么结构吧:
(1) charAt(int n) 返回字符串内n位置的字符,第一个字符位置为0,
最后一个字符的位置为length()-1,访问错误的位置会扔出一块大砖头:
StringIndexOutOfBoundsException 真够大的
(2) concat(String str) 在原对象之后连接一个 str ,但是返回一个新的 String 对象
(3) EqualsIgnoreCase(String str) 忽略大小写的 equals 方法
这个方法的实质是首先调用静态字符方法toUpperCase() 或者 toLowerCase() ,将对比的两个字符转换,然后进行 == 运算
(4) trim() 返回一个新的对象,它将原对象的开头和结尾的空白字符切掉,同样的,如果结果与原对象没有差别,则返回原对象
(5) toString() String 类也有 toString() 方法吗?
真是一个有趣的问题,可是如果没有它,你的 String 对象说不定真的不能用在System.out.println() 里面啊
小心,它返回对象自己
String 类还有很多其他方法,掌握他们会带来很多方便
也会有很多困惑,所以坚持原则,是最关键的
4. 我想买一匹更好的马
来购买更驯服温和的 String 的小弟 StringBuffer 吧
这时候会有人反对:它很好用,它效率很高,它怎么能够是小弟呢?
很简单,它的交互功能要比 String 少,如果你要编辑字符串,它并不方便,你会对它失望,但这不意味着它不强大
public final class String implements Serializable, Comparab