大家先來看看一段奇怪的程序:
public class TestString {
public static void main(String[] args) {
String s1 = "Monday";
String s2 = "Monday";
}
}
這個程序真是簡單??!可是有什么問題呢?
1. 來自 String 的憂慮
上面這段程序中,到底有幾個對象呢?
可能很多人脫口而出:兩個,s1 和
s2
為什么?
String 是 final 類,它的值不可變。
看起來似乎很有道理,那么來檢測一下吧,稍微改動一下程序
就可以看到結果了:
public class TestString {
public static void main(String[] args) {
String s1 = "Monday";
String s2 = "Monday";
if (s1 == s2)
System.out.println("s1 == s2");
else
System.out.println("s1 != s2");
}
}
呵呵,很多人都會說已經不止兩個對象了
編譯并運行程序,輸出:s1 == s2
啊!
為什么 s1 == s2 ?
== 分明是在說:s1 與
s2 引用同一個 String 對象
-- "Monday"!
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 s2");
}
}
我們將 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 對象的值了
真是爽啊,又快又方便!
String 啊 String ,讓我說你什么好呢?
你為我們 Java 程序員帶來所有的困擾還不夠嗎?
看看 String 這一次又怎么鬧事兒吧
1. 回顧一下壞脾氣的
String 老弟
例程1:
class Str {
public static void main(String[] args) {
String s = "Hi!";
String t = "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
WHY!!!
把程序簡單的更改一下:
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
Oh MyGOD!!!
誰來教訓一下這個 String ??!
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,
Comparable, CharSequence
public final class StringBuffer implements Serializable,
CharSequence
很明顯的,小弟少了一些東東,不過這不會干擾它的前途
StringBuffer 不是由 String 繼承來的
不過要注意兄弟它也是 final 啊,本是同根生
看看他的方法吧,這么多穩定可靠的方法,用起來比頑皮的 String 要有效率的多
?nbsp;
Java 為需要改變的字符串對象提供了獨立的
StringBuffer 類
它的實例不可變(final),之所以要把他們分開
是因為,字符串的修改要求系統的開銷量增大,
占用更多的空間也更復雜,相信當有10000人擠在一個狹小的游泳池里游泳
而岸邊又有10000人等待進入游泳池而焦急上火
又有10000人在旁邊看熱鬧的時候,你這個
String 游泳池的管理員也會焦頭爛額
在你無需改變字符串的情況下,簡單的 String 類就足夠你使喚的了,
而當要頻繁的更改字符串的內容的時候,就要借助于宰相肚里能撐船的
StringBuffer 了
5. 宰相肚里能撐船
(1) length() 與 capacity()
String 中的 length() 返回字符串的長度
兄弟 StringBuffer 也是如此,他們都由對象包含的字符長度決定
capacity()呢?
public class TestCapacity {
public static void main(String[] args){
StringBuffer buf = new StringBuffer("it was the age
of wisdom,");
System.out.println("buf = " + buf);
System.out.println("buf.length() = " +
buf.length());
System.out.println("buf.capacity() = " +
buf.capacity());
String str = buf.toString();
System.out.println("str = " + str);
System.out.println("str.length() = " +
str.length());
buf.append(" " +
str.substring(0,18)).append("foolishness,");
System.out.println("buf = " + buf);
System.out.println("buf.length() = " +
buf.length());
System.out.println("buf.capacity() = " +
buf.capacity());
System.out.println("str = " + str);
}
}
程序輸出:
buf = it was the age of wisdom.
buf.length() = 25
buf.capacity() = 41
str = it was the age of wisdom
str.length() = 25
buf = it was the age of wisdom, it was the age of
foolishness,
buf.length() = 56
buf.capacity() = 84
str = it was the age of wisdom,
可以看到,在內容更改之后,capacity也隨之改變了
長度隨著向字符串添加字符而增加
而容量只是在新的長度超過了現在的容量之后才增加
StringBuffer 的容量在操作系統需要的時候是自動改變的
程序員們對capacity所能夠做的僅僅是可以在初始化
StringBuffer對象的時候
為它強行的分配一個固定的capacity,但是之后,它愿不愿以改變就完全看自己的了
capacity 會隨著 length 超出而改變,總之,它總是要比
length 大
“哦親愛的小馬,快快啟程吧,幫我把這84個箱子運到那邊去。”
(!@#$$%% 這么多?。?/span>
“不過里面只有56個雞蛋。”
(!@#$$%% 虐待啊)
6. 把好你的舵不要翻船
StringBuffer的胃口看起來很好啊
看起來似乎它可以隨意的變成一艘航空母艦
不過請注意:
capacity 的每一次更改和變化,整個對象必須被重建并且移動到另外一個內存區
為了避免類似的溢出,最好在初始化的時候為他分配足夠的容量
如果你是船長,在航行中突然下令:“我們準備棄船,換另外一艘大船去啦!”
你的水手們怎么想?“讓我們自殺嗎?”
所以出發前盡量準備一艘合適的船,不要超載,也不要太大
千萬不要在中途翻船啊!
StringBuffer 還有一個炫耀的調皮方法:reverse()
它可以讓它肚子里面的東西反一個個兒
7. 大馬吃小馬
哦,天哪,String 和
StringBuffer 用誰都會使性子
應該如何是好呢?
(1)如果你的 String 僅出現極少數次,隨他們去吧,畢竟草原很遼闊
(2)如果他們數目驚人混亂不堪擠作一團到處破壞,
將他們 intern() ,學會游泳比淹死了強
另外配合著 StringBuffer 的使用,它很像這群亂馬的頭頭
可以舒舒服服的調教哪些野性的 String ,把他們頭接尾、尾接頭的組合起來
形成一個團體,更容易控制和管理(不過令人沮喪的是它的編輯功能不太好)
不過要小心,雖然StringBuffer 的肚子很大,但是不要把它撐破了
適當的給它一個空間,它會發揮更好的作用
(3) 小心謹慎的對待
== 和 equals()
千萬不要忘了本,他們都是對象
你可以用各種高效率的辦法進行嘗試(intern() 然后
==)
但是在最終的原則上要把握好
(4) String 和 StringBuffer不可以互相使用
equals()
不要忘了他們不是同類
小結:
好了,說了這么多
我想我們終于可以指揮著我們的千軍萬馬馳騁在 Java 的大草原上了
String 還有 StringBuffer ,都可以成為我們手中的有力工具
Which two create an
instance of an array? (Choose two)
A. int[] ia = new int[15];
B. float fa = new
float[20];
C. char[] ca = “Some
String”;
D. Object oa = new
float[20];
E. int ia[][] = { 4, 5, 6,
}, { 1, 2, 3 };
[答案]:AD
Question No: 11
Which two demonstrate an “is a” relationship? (Choose
Two)
A. public interface Person { }
public class Employee extends Person { }
B. public interface Shape { }
public class Employee extends Shape { }
C. public interface Color { }
public class Employee extends Color { }
D. public class Species { }
public class Animal (private Species species;)
E. interface Component { }
Class Container implements Component (
Private Component[ ] children;
)
Answer: D, E
class Test{
public int aMethod (){
static int i = 0;
i++;
return I;
}
public static void main(String[] args){
test test = new test();
test.aMethod();
int j = test.aMethod();
System.out.println(j);
}
}
應該是compilation will fail
class Test{
static int i = 0;
public int aMethod (){
i++;
return i;
}
這樣就對了!??!
class s extends Thread{
int j=0;
public void run() {
try{Thread.sleep(5000);}
catch(Exception e){}
j=100;
}
public static void main(String args[])
{
s t1=new s();
t1.start();
System.out.println(t1.j);
}
}
what you have to do to ensure that 'j' will print 100
A:you have make t1 as Daemon Thread
B:You have join the t1 to main
C:You have to suspend the main when the thread starts
and resume it after the value of 'j' is set to 100
D:You have to interrupt the main thread
選B,、
class S extends Thread{
int j=0;
public void run() {
try{Thread.sleep(1000);}
catch(Exception e){}
j=100;
System.err.println("S end");
}
public static void main(String args[])
{
S t1=new S();
t1.start();
try
{
t1.join();
}
catch(InterruptedException e)
{
}
System.err.println(t1.j);
System.err.println("main end");
}
}
73. which two cannot directly cause a thread to stop
executing?
A.calling the yield method
B.calling the wait method on an object
C.calling the notify method on an object
D.calling the notifyAll method on an object
E.calling the start method on another thread object
posted on 2005-09-16 10:44
我的java天地 閱讀(390)
評論(0) 編輯 收藏 所屬分類:
體會