JWorld@TW the best professional Java site in Taiwan
      註冊 | 登入 | 全文檢索 | 排行榜  

» JWorld@TW » Java 新手區  

按列印兼容模式列印這個話題 列印話題    把這個話題寄給朋友 寄給朋友    訂閱主題
reply to topicthreaded modego to previous topicgo to next topic
本主題所含的標籤
無標籤
作者 閒聊 -- 名稱,參考,和物件 [精華]
swanky

暴走熊

版主

發文: 461
積分: 9
於 2003-08-21 08:15 user profilesend a private message to usersend email to swankyreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
轉錄自java連線版

作者: TAHO (癡人) 看板: java
標題: 閒聊 -- 名稱,參考,和物件
時間: Mon Dec 17 16:07:34 2001

在看版上的佈告時,常常看到一些把 名稱 參考 以及 物件 之間搞混,
而產生困擾的狀況,所以我再來閒聊一下這方面的話題好了。
(以 reference type 的變數為例,非 primitive type 變數)

以下面這兩個敘述為例:

1
2
    StringBuffer sb = new StringBuffer("Test");
    sb.append(" names!");


我想一般的書會這樣解釋," 產生一個 StringBuffer 類別的物件 sb "
" 呼叫物件 sb 的 append 方法將字串附加進物件中 ",這兩句話基本上並沒
有錯,但是卻很容易造成初學者的誤會,以為 "sb" 就是物件。

其實這是一種語言描述不精確的問題,這小小的誤會可能會造成之後學習
過程中很大的困擾。如果要精確的說,那並不能稱 sb 為物件,sb 這兩個字
母只不過是一個 name,也就是一個 "名稱" 而已,方便我們拿來稱呼某個物
件的名稱,也就是說 "sb 代表一個物件,但 sb 本身不是物件"。就像我們每
個人都有一個名字,你也可以替你家的貓,狗,甚至是電腦取一個名字。如果
你家的電腦叫做 "小花花",那這個 "小花花" 只是用來幫助我們提到你家的
電腦時用來稱呼的名詞,"小花花" 這三個字並不一台電腦,也不是你家的電
腦,它只是一個名字。

那物件在那裡呢?

在 Java 中,物件是被藏起來的,除非你手上握有關於物件的線索,否則
這個就永遠無法跟物件聯絡,而且就算你握有物件的線索,也無法 "直接" 操
控這個物件,而必須要通過這個線索去控制物件。如果有位媽媽自己生產了一
個小孩,沒有醫院的出生證明,沒有名字,沒有身份資料,那對政府來說,這
個小孩就等於是不存在。如果政府有小孩的相關資料,他可以寫信請小孩打預
防針,可以派人去家庭訪問,可以透過某種方式操控小孩,但是政府無法親身
直接作這些事( "政府自己來家庭訪問 而不是派人來家庭訪問" 這句話聽起
來就很奇怪吧)。程式設計師就是政府,他可以透過某種東西來操控物件,而
沒有辦法直接控制物件。

這種東西就稱為 "參考"。

參考就是物件的線索,我們可以透過參考來找到物件,就像透過身份證號
碼來找人一樣。如果我們失去了物件的參考,那我們就喪失了尋找物件的線索
,那這個物件對程式設計師來說就等於是不存在了,即使這物件仍在記憶體某
處,也一樣再也無法找到它。

那 "參考" 在那裡?

參考就放在名稱裡。畫成圖示的話是這樣:

1
2
3
4
5
6
    ____________
    |          |
    |          |
    |   參考 -----------> 某物件
    |          |
    |__________|


框框即為 "名稱"。"參考的樣式" 以及 "物件的樣式" 稱為 "型別"。所以:

1
    new StringBuffer("Test");


會在記憶體的某處產生一個物件,而這個物件的樣式是 StringBuffer 的格式
。同時敘述會產生一個要找到物件的線索,也就是這個物件的參考,但是這個
敘述並沒有將此參考儲存起來,而將這個參考隨意丟棄,於是這個物件生成的
同時也就失蹤了,從此再也找不到這個物件。為了避免這種狀況,我們必須先
製造一個容器放置這個參考。

1
    StringBuffer sb;


這個敘述做了一個名字為 sb 的容器,其樣式為 StringBuffer 樣式,所以他
可以放置 StringBuffer 樣式的東西。於是:

1
    sb = new StringBuffer("Test");


就是在產生一個物件的同時,將這個物件的參考放進 sb 這個容器中。因為參
考放在 sb 中,所以以後就可以隨時利用 sb,拿到 sb 裡面的參考,藉由參
考來找到物件。我們可以將上面兩個式子合寫成:

1
    StringBuffer sb = new StringBuffer("Test");


做的事情是一樣,只是打字少打幾個字,排列方式不太一樣而已。所以當我們
看到:

1
    sb.append(" names!");


時,事實上,他是利用 sb 去拿到存放在 sb 裡面的參考,再利用這個參考去
找到某一個物件,然後執行這個物件的 append() 方法。平常所稱呼的 "物件
sb" 只是一個方便用的稱呼方式,並非表示 sb 本身就是物件。搞清楚這一點
之後再看看一般初學者會感到疑問的敘述式:

1
2
3
4
5
6
    String str1;
    String str2;
 
    str1 = new String("First");
    str2 = str1;
    str2 = new String("Second");


為甚麼 str1 還是原來的 "First" 而不會變成 "Second" 呢?聰明的你知道
原因了嗎?因為 str2 = str1; 這一個敘述,是將 str1 裡面所放置的參考
"複製" 一份,放到 str2 裡面。這時候物件只有一個,但是有兩個參考都指
向同一個物件,這兩個參考分別放在 str1 跟 str2 中。當執行 str2 =
new String("Second"); 的時候,會將新的物件的參考放入 str2 中,把原先
舊的參考覆蓋掉,完全沒有影響到 str1 中的參考,所以變成有兩個參考分別
指向兩個不同的物件。

不知道這種說法,會不會讓初學者更了解 Java 的機制呢?還是更模糊了
? @_@|||


reply to postreply to post
作者 閒聊 -- 名稱,參考,和物件 part II [Re:swanky]
swanky

暴走熊

版主

發文: 461
積分: 9
於 2003-08-21 08:18 user profilesend a private message to usersend email to swankyreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
轉錄自java連線版

作者: TAHO (癡人) 看板: java
標題: 閒聊 -- 名稱,參考,和物件 part II
時間: Tue Dec 18 02:21:55 2001

如果以之前說的觀念,將『名稱』『參考』『物件』這三個名稱分隔清
楚,那在討論轉型的時候就會更加明確了。

以這個例子來說:

1
    Object o = (Object) new String("This is a String.");


一般的書可能會說成『將這個 String 型別的物件轉型成 Object 型別的物
件』,其實這樣說也是不完全正確的。如果你還記得的話應該可以發現:

1
    new String("This is a String.");


這個敘述除了會在電腦的記憶體某處產生一個物件之外,他還會傳回指向這
個物件的『參考』。而且查書也可以發現 new運算 的執行優先權高於強制轉
型的運算,而轉型運算會優於 = 的指定運算,也就是說第一個式子會先運算
new 的部分,然後把結果做轉型運算,最後再做指定運算。所以很明顯的

1
    (Object) .....;


這個運算並不是將物件做轉型,而是將 new 運算的結果做轉型,換句話說就
是把『參考』轉型。所以你發現了嗎?

『物件』根本不會轉型,會轉型的是『參考』。

這就是我之前在其它討論串中所說的,不管如何轉型,Java 都會記住物件原
來是屬於什麼類別的,因為物件從頭到尾都沒有變過,變的是參考。至於
JVM 如何處理『參考』轉型後對物件方法以及物件欄位的呼叫,就跟 JVM
如何處理類別的程式碼,以及 JVM 如何處理物件的資料有關,這邊就不多加
討論。

實際上,原來的式子不強制轉型也是可行的。如:

1
    Object o = new String("This is a String");


為什麼 JVM 允許這樣做呢?因為 String 是 extends Object 的。讓我舉個
例子吧。之前說過變數是一個容器,一個用來放置參考的容器,如果我們有
一個杯子,這個杯子規定只能放入液體,那麼你可以把水放進去,也可以把
油放進去,也可以把果汁放進去,因為這些東西都是液體,也就是說 水 油
跟 果汁 都是 extends 液體,所以非常直覺的,放這些東西進去都不會出現
問題。但是如果今天是一顆蘋果,或是一袋花生,那就不能被塞到杯子裡,
因為這些東西根本不是液體,不能放進去也是很正常的。如果今天我們把蘋
果強制幾成果汁,把花生強制炸成花生油,那就可以放置。如果今天要塞進
去的是一把火,因為他跟液體扯不上關係,所以他本身不能放進去這個杯子
,火也沒有辦法強制變成液體,這時候火就是完全無法放入杯子裡的。所以
如果現在有一個式子:

1
    String str = (String) o;


這是可行的,因為 o 這個變數裡面的參考指向的是 String 的物件,所以可
以把 o 裡面所包含的參考轉型為 String 的格式,然後再把這個參考複製一
份放入 str 這個變數中。但是如果是:

1
    System s = (System) o;


那就會出問題。因為 o 變數裡面的參考指向的是 String 物件,如果將這個
參考變成 System 格式,那就再也無法參考到 String 物件了,所以這個轉
型會發生例外。


reply to postreply to post
作者 Inner Class 介紹 [Re:swanky]
swanky

暴走熊

版主

發文: 461
積分: 9
於 2003-08-21 08:23 user profilesend a private message to usersend email to swankyreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
轉錄自java連線版

作者: TAHO (癡人) 看板: java
標題: Re: 閒聊 -- 名稱,參考,和物件 part II
時間: Mon Dec 24 12:25:06 2001

※ 引述《compuwong@yahoo.com (compuwong)》之銘言:
> taho, 可否說說inner class 呢?例如有什麼作用,四種inner class 又有何分別
> ......thx ar..^^..因為我還是分不清何時用 那種inner class 好..

inner class 分為四種
如果不要太在意 "class" 這個字眼的話
可以很清楚的發現 他跟 field method 或是 local 變數 的地位是一樣的
就跟變數(物件)宣告的情況分為四種是一樣的意思

1
2
3
4
5
6
7
8
9
10
public class Test
{
    public static String fieldA;
    public String fieldB;
 
    public static void methodA() { ... }
    public void methodB() { ... }
 
    ...
}


上面的例子 fieldA fieldB methodA methodB 都是 類別 Test 的成員
同理 我們也可以加上 class 的成員

1
2
    public static class ClassA{ ... }
    public class ClassB{ ... }


同樣的 ClassA 是跟類別相關 而 ClassB 是跟物件相關
前者是 靜態內部類別 ( 對比於 靜態欄位 )
後者是 成員類別 ( 對比於 成員欄位 )
其用法與地位可以比照 fieldA 跟 fieldB

同樣的 我們可以在 method 中 或是 static block 中
像在宣告 區域變數 一樣的宣告 類別

1
2
3
4
5
6
7
public void method()
{
    public String varC;
    public class ClassC{ ... }
 
    ...
}


或是

1
2
3
4
5
public void method()
{
    methodD( new Date() );
    methodD( new ClassD(){ ... } );
}


看起來是不是很像呢?
前者就是 區域類別 ( 對比於 區域變數 )
後者為 匿名類別 ( 就像沒有變數名稱的物件 )

至於使用的時機 就跟你為甚麼要宣告 field 或是 區域變數 一樣囉
如果內部類別 是直接跟外層類別相關 在 JVM 中只維持一份 class 物件
那就是 靜態內部類別 (static field)
如果內部類別 是跟外層類別的 "物件" 相關
每個外層類別的物件 都維持一份內部類別的 class 物件
那就是 成員類別 ( non-static field)
如果這內部類別的視野只需在某一 method 的敘述過程中出現
那就需要使用 區域類別 ( 區域變數 )
如果內部類別只需在某一 method 中出現一次
那可以只用 匿名類別 ( 匿名物件 )

當然這些內部類別的使用上有一些規範和限制
寫程式時要特別去注意一下就是了

PS: 內部類別應該是為了讓寫程式更輕鬆方便而設計的
除非有特殊需求 否則不需要強迫自己把程式寫成內部類別的樣子吧
就算是 awt 或是 swing 程式中大量使用的 匿名類別
如果寫成一般類別 還是可以執行的很好啊


reply to postreply to post
作者 Re:閒聊 -- 名稱,參考,和物件 [Re:swanky]
item1394

松隆子



發文: 81
積分: 4
於 2003-10-07 20:41 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class Excel
{
    public static void main(String argv[])
    {
        A a = new B();
        B b = (B) a;
        C c = new A();
        D d = (D) c;
     }
}
 
class A {}
class B extends A {}
class C extends B {}
class D extends A {}


嗯...我在看過上面的文章後,剛巧碰上了同樣的問題
我想在這邊發表一下看法,不知道是否正確,請大家多多指較,thx

首先
1
A a = new B();

new B()產生一個B類別物件,同時A a產生一個參考,而用"="將兩個連接起來

接著
1
B b = (B) a;

則是將參考轉型成B類別? 再丟給b
1
C c = new A();

由於 C extends B and B extends A
所以在此必須改成
1
C c = (C) new A();

然後
1
D d = (D) c;

因為C與D之間並沒有繼承關係所以沒辦法轉型?


item1394 edited on 2003-10-08 13:41
reply to postreply to post
作者 Re:閒聊 -- 名稱,參考,和物件 [Re:item1394]
TAHO

可愛吧∼∼

版主

發文: 271
積分: 7
於 2004-01-07 05:28 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
item1394 wrote:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class Excel
{
    public static void main(String argv[])
    {
        A a = new B();
        B b = ( B ) a;
        C c = new A();
        D d = (D) c;
     }
}
 
class A {}
class B extends A {}
class C extends B {}
class D extends A {}


嗯...我在看過上面的文章後,剛巧碰上了同樣的問題
我想在這邊發表一下看法,不知道是否正確,請大家多多指較,thx

首先
1
A a = new B();

new B()產生一個B類別物件,同時A a產生一個參考,而用"="將兩個連接起來

接著
1
B b = ( B ) a;

則是將參考轉型成B類別? 再丟給b
1
C c = new A();

由於 C extends B and B extends A
所以在此必須改成
1
C c = (C) new A();



這有很大很大的問題吧? 這邊編譯會過 可是 runtime 會錯誤
new A() 之後,物件是屬於型別 A
型別 A 的物件,無論如何都無法變成型別 C 的

item1394 wrote:
然後
1
D d = (D) c;

因為C與D之間並沒有繼承關係所以沒辦法轉型?


是的,這是編譯時期的檢查使然,實際上你的問題好像不太存在
class A 有兩個繼承的分支
要把其中一個分支的物件轉成另一個分支的物件? 怎麼想都怪怪的∼∼


browser edited on 2004-01-07 05:33
reply to postreply to post
作者 Re:閒聊 -- 名稱,參考,和物件 [Re:item1394]
java_sai





發文: 11
積分: 0
於 2004-10-23 18:13 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
*補充說明:如以下寫法編譯器容許,但runtime也會產生ClassCastException

1
2
3
4
5
6
7
8
9
10
11
12
13
class A {}
class B1 extends A {}
 
class Sai {
 
    public static void main (String[] args) {
       A a = new A();  
       B1 b = new B1();
       b = (B1)a;
    }
}
 


tekwei edited on 2004-10-23 19:03
reply to postreply to post
邁向神乎其技的境界!
» JWorld@TW »  Java 新手區

reply to topicthreaded modego to previous topicgo to next topic
  已讀文章
  新的文章
  被刪除的文章
Jump to the top of page

JWorld@TW 本站商標資訊

Powered by Powerful JuteForum® Version Jute 1.5.8