小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

類、抽象類、接口、繼承和對象(java)

 執(zhí)著男孩 2006-09-13

 


這不是什么教材,筆者有時會在論壇上瞧瞧,看到不少初學(xué)者問到很多問題,這些問題是java程序員應(yīng)該懂得的,而一般書上不會講到或者一筆帶過的知識。因此斗膽涂鴉一篇文章,把想說的在這里一口氣說完。這也是本人第一次寫技術(shù)性的文章,文筆不暢之外,還請各位見諒。


首先講清楚類和對象的區(qū)別。


類是廣泛的概念,表示一個有共同性質(zhì)的群體,而對象指的是具體的一個實實在在的東西。例如,“人”是一個類,它可以表示地球上所有的人;而“張三”、“李四”、“愛因斯坦”等則是一個個的對象,或者說它們是“人”這個類的一個個實例。在 Java 中,我們可以定義類,然后創(chuàng)建類的對象。


例如:
// 聲明一個類“Human”
class Human{
    private String name;
    public String getName(){
        return name;
    }
    public void setName(String value){
        this.name = value;
    }
    //......
}


創(chuàng)建一個類:
Human human = new Human();


 


其次,很多人對對象和對象的引用認識模糊
引用是程序操作對象的句柄,相當(dāng)于C和C++中的指針。
前面說了,對象是一個實實在在的東西,比如前面的代碼:
Human human = new Human();
程序執(zhí)行到這里之后,java虛擬機將會在內(nèi)存中創(chuàng)建一個 Human 對象,并將這個對象的引用賦給 human 變量。這里有兩步,首先是創(chuàng)建 Human 對象,然后把創(chuàng)建的對象的引用賦給 human 變量。
如果聲明了一個對象的引用,但沒有將對象賦值給它,則這個引用指向了空的對象,或者說引用了不存在的對象。這時如果想通過這個引用訪問對象,則會拋出空指針異常,例如:
Human human;
//......
human.setName("張三");


 


下面重點談一談類、抽象類、接口和繼承之間的關(guān)系
不少細心的初學(xué)者在論壇上問類似這樣的問題:
1、接口不實現(xiàn)方法,但我卻在程序中可以調(diào)用接口的方法,這是為什么?比如 java.sql 包中的 Connection、Statement、ResultSet 等都是接口,怎么可以調(diào)用 它們的方法呢?
2、抽象類不能實例化,但是jdk中卻有很多抽象類的對象,這是為什么?比如 System.in 是一個 InputStream 類型對象,但 InputStream 是抽象類,怎么可以得到它的對象呢?


不管怎么樣,大家應(yīng)該明白一點:不管是抽象類中的抽象方法,還是接口中定義的方法,都是需要被調(diào)用的,否則這些方法定義出來就沒有意義了。


可能有很多書上沒有提到,或者提到了而讀者沒有注意到這一點:
一個子類如果繼承了它的基類,則表示這個類也是其基類的一種類型,這個子類的一個對象是子類類型,并且同時也是其基類的一個對象,它也具有基其類的類型;一個類如果實現(xiàn)了一個接口,則表示這個類的一個對象也是這個接口的一個對象。


可能這樣說不太好懂,又是子類、基類、類型、接口什么的,容易搞混。其實舉個現(xiàn)實的例子你就會覺得其實很簡單:
如果“人”是一個基類,則“男人”是“人”的一個子類。如果“張三”是一個“男人”,也就是說“張三”是“男人”的一個對象,那么顯然“張三”也是“人”這個基類的一個對象。


明白了這一點,就容易理解為什么我們可以得到抽象類的對象了:原來我們得到的抽象類的對象其實是它的已經(jīng)實現(xiàn)了抽象方法的子類或子孫類的一個對象,但我們拿它當(dāng)它的抽象類的基類來用。比如“人”這個類,每個人都會“悲傷”,男人悲傷的時候抽煙、喝酒,女人悲傷的時候哭泣、流淚。由于不同的子類在“悲傷”時所進行的動作不一樣,因此這個動作(方法)在基類中不好實現(xiàn),但基類中又需要有這個方法,因此,“人”這個類就可以定義一個抽象方法“悲傷”,由其子類“男人”和“女人”來實現(xiàn)“悲傷”這個方法。但是調(diào)用者只把男人和女人的對象當(dāng)作其基類“人”的一個對象,調(diào)用它的“悲傷”方法。
讀者可以去體驗一下 jdk 的抽象類 java.lang.Process :
Runtime runtime = Rumtime.getRuntime();
Process process = rumtime.exec("notepad.exe");
Class cls = process.getClass();
System.out.println(cls.getName());
這時會打印出 process 類的名字,如果在 Windows 下它會是一個類似于 *Win32* 的名字,它是 Process 的一個子類。因為 process 類用于管理打開的進程,而在不同的操作系統(tǒng)上都有不同的實現(xiàn),因此它把方法定義為 Process 的抽象方法,而具體的操作只能由對應(yīng)在不同操作系統(tǒng)下的子實現(xiàn)。



下面來談接口,我們知道接口只定義了一些方法,而沒有實現(xiàn)這些方法。而其實,接口是一個規(guī)范,它規(guī)定了實現(xiàn)這個接口所要做的事情,或者說規(guī)定了實現(xiàn)接口的類必須具備的能力(也就是方法)。
那么我們可以這樣對比:
某種類型的駕駛執(zhí)照,規(guī)定了拿到這個駕照的人必須能夠“開小汽車”和“開公共汽車”。那么我們認為這個駕照是一個接口,它規(guī)定了實現(xiàn)它的類所必須有的能力。
我們可以定義一個類 Driver,繼承自 Human,然后實現(xiàn)“駕照持有者”這個接口:
public interface DriverHolder{
    public void driverCar();
    public void driverBus();
}
public class Driver extends Human implements DriverHolder{
    public void driverCar(){
        // ......
    }
    public void driverBus(){
        // ......
    }
}



這樣一來,一個“Driver”對象,它同時也是一個 DrivreHolder 對象。即一個司機(Driver)同時是一個駕照執(zhí)持有者對象。在程序中我們可以這樣:
DriverHolder driverholder = new Driver();
driverholder.driverCar();


這樣我們就解釋了為什么“接口沒有實現(xiàn)方法,卻可以得到接口類的對象”的問題。


但是這樣一來,肯定有人會問:為什么要定義一個接口呢,為什么不直接把這個方法定義到 Driver 類中去,然后 Driver driver = new Driver(); 一樣可以調(diào)用它的 driverCar(); 和 driverBus() 方法,這樣做豈不是方便得多?


這是因為java是單繼承的,它只能繼承于一個類,這樣它的類型就只限于其基類或者基類的基類。但是java可以實現(xiàn)多個接口,這樣它就可以有很多個接口的類型。就象一個人,它繼承自“脊椎動物”這個類,而“脊椎動物”又繼承自“動物”這個類,因此“張三”是個人,他是一個“脊椎動物”,當(dāng)然他也是一個“動物”。但他可以繼承很多個接口,比如拿駕駛執(zhí)照之后,他就是“駕照持有者”類型,他也可以拿英語六級證書,這樣他就是一個六級證書持有者等等。


明白這一點之后,我們來看一看 java 的事件機制。
java.awt.Button 類有一個 addActionListener(ActionListener l);方法。這個方法傳入的是一個接口類型:ActionListerner,在實際中,我們需要實現(xiàn) ActionListener 接口,并且把實現(xiàn)這個接口的類的對象引用作為參數(shù)傳入。這樣,Button對象就得到了一個 ActionListener 對象,它知道這個 ActionListener 對象有一個 actionPerformed 方法,或者說它有處理 Action 事件的能力,當(dāng) Action 事件發(fā)生時,它就可以調(diào)用這個對象的 actionPerformed 方法。


比如一般我們會這樣做:
public class TestButton extends Frame implements ActionListener{
    private Button btn1 = new Button();
    //......
   
    public TestButton(){
        btn.addActionListener(this);
 this.add(btn);
    }
   
    public void actionPerformed(ActionEvent e){
 
    }
}


現(xiàn)在我們假設(shè) ActionListener 不是接口,而是一個類。那么我們只能繼承 ActionListener 類,并且重寫 actionPerformed 方法。但是java是單繼承的,如果類繼承了 ActionListener 類,那么它就不能繼承其它的類(Frame 類)了,而不從 Frame 類繼承的話,又怎么創(chuàng)建窗體,怎么把 Button 放到窗體中去呢?



其實接口不完全是為了解決 java 的單繼承問題,它在某種程度上可以達到調(diào)用和實現(xiàn)細節(jié)的分離。
比如說,中國的民用電規(guī)范是一個接口:平均電壓220V、50Hz、Sin 交流電,水力發(fā)電廠、火力發(fā)電廠、核電廠,還有小型的柴油發(fā)電機如果按這個規(guī)范發(fā)電,則表示它們實現(xiàn)了這個民用電源的接口;冰箱、電視、洗衣機等家用電器使用這些電源,表示它們在調(diào)用這個接口。在這里,家用電器不管電從哪里來,只要它符合民用電源的規(guī)范就好,電源也不管它發(fā)的電用于什么工作,只管提供電源。


再回過頭來看看 Button 的事件機制。要知道,Button 要保證所有的 action 事件發(fā)生時,程序員都可以在他的代碼中處理它,圖書館管理系統(tǒng)、收銀系統(tǒng)、進銷存等等等等等等。而接口就可以做到這一點:找一個類實現(xiàn) ActionListener 接口,并且讓 Button 得到這個類的對象的引用( 調(diào)用 addActionListener 方法),從而當(dāng)Action事件發(fā)生時,button 創(chuàng)建一個包含了事件信息的對象(ActionEvent),然后調(diào)用這個接口對象的方法,到底怎么處理這次事件,這就是實現(xiàn)接口的類的事情了。在這里,Button 絲毫不了解 actionPerformed 方法中到底干了什么事情,也不應(yīng)該知道。Button 與具體的業(yè)務(wù)邏輯完全分離開了,它可以應(yīng)用到所有的場合。

 


    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多