<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    qileilove

    blog已經(jīng)轉(zhuǎn)移至github,大家請?jiān)L問 http://qaseven.github.io/

    Java 中的內(nèi)部類和匿名類

     Java 內(nèi)部類有什么好處?為什么需要內(nèi)部類?
      首先舉一個簡單的例子,如果你想實(shí)現(xiàn)一個接口,但是這個接口中的一個方法和你構(gòu)想的這個類中的一個方法的名稱,參數(shù)相同,你應(yīng)該怎么辦?這時候,你可以建一個內(nèi)部類實(shí)現(xiàn)這個接口。由于內(nèi)部類對外部類的所有內(nèi)容都是可訪問的,所以這樣做可以完成所有你直接實(shí)現(xiàn)這個接口的功能。
      不過你可能要質(zhì)疑,更改一下方法的不就行了嗎?
      的確,以此作為設(shè)計(jì)內(nèi)部類的理由,實(shí)在沒有說服力。
      真正的原因是這樣的,java 中的內(nèi)部類和接口加在一起,可以的解決常被 C++ 程序員抱怨 java 中存在的一個問題??沒有多繼承。實(shí)際上,C++ 的多繼承設(shè)計(jì)起來很復(fù)雜,而 java 通過內(nèi)部類加上接口,可以很好的實(shí)現(xiàn)多繼承的效果。
      內(nèi)部類:一個內(nèi)部類的定義是定義在另一個內(nèi)部的類。
      原因是:
      1.一個內(nèi)部類的對象能夠訪問創(chuàng)建它的對象的實(shí)現(xiàn),包括私有數(shù)據(jù)。
      2.對于同一個包中的其他類來說,內(nèi)部類能夠隱藏起來。
      3.匿名內(nèi)部類可以很方便的定義回調(diào)。
      4.使用內(nèi)部類可以非常方便的編寫事件驅(qū)動程序。
      1.內(nèi)部類
      提起 Java 內(nèi)部類(Inner Class)可能很多人不太熟悉,實(shí)際上類似的概念在 C++ 里也有,那就是嵌套類(Nested Class),關(guān)于這兩者的區(qū)別與聯(lián)系,在下文中會有對比。內(nèi)部類從表面上看,就是在類中又定義了一個類(下文會看到,內(nèi)部類可以在很多地方定義),而實(shí)際上并沒有那么簡單,乍看上去內(nèi)部類似乎有些多余,它的用處對于初學(xué)者來說可能并不是那么顯著,但是隨著對它的深入了解,你會發(fā)現(xiàn)Java的設(shè)計(jì)者在內(nèi)部類身上的確是用心良苦。學(xué)會使用內(nèi)部類,是掌握J(rèn)ava高級編程的一部分,它可以讓你更優(yōu)雅地設(shè)計(jì)你的程序結(jié)構(gòu)。下面從以下幾個方面來介紹:
      * 第一次見面
    public interface Contents {
    int value();
    }
    public interface Destination {
    String readLabel();
    }
    public class Goods {
    private class Content implements Contents {
    private int i = 11;
    public int value() {
    return i;
    }
    }
    protected class GDestination implements Destination {
    private String label;
    private GDestination(String whereTo) {
    label = whereTo;
    }
    public String readLabel() {
    return label;
    }
    }
    public Destination dest(String s) {
    return new GDestination(s);
    }
    public Contents cont() {
    return new Content();
    }
    }
    class TestGoods {
    public static void main(String[] args) {
    Goods p = new Goods();
    Contents c = p.cont();
    Destination d = p.dest("Beijing");
    }
    }



      在這個例子里類 Content 和 GDestination 被定義在了類 Goods 內(nèi)部,并且分別有著 protected 和 private 修飾符來控制訪問級別。Content 代表著 Goods 的內(nèi)容,而 GDestination 代表著 Goods 的目的地。它們分別實(shí)現(xiàn)了兩個接口 Content 和 Destination。在后面的 main 方法里,直接用 Contents c 和 Destination d 進(jìn)行操作,你甚至連這兩個內(nèi)部類的名字都沒有看見!這樣,內(nèi)部類的第一個好處就體現(xiàn)出來了??隱藏你不想讓別人知道的操作,也即封裝性。
      同時,我們也發(fā)現(xiàn)了在外部類作用范圍之外得到內(nèi)部類對象的第一個方法,那就是利用其外部類的方法創(chuàng)建并返回。上例中的 cont() 和 dest() 方法就是這么做的。那么還有沒有別的方法呢?當(dāng)然有,其語法格式如下:
      outerObject=new outerClass(Constructor Parameters);
      outerClass.innerClass innerObject=outerObject.new InnerClass(Constructor Parameters);
      注意在創(chuàng)建非靜態(tài)內(nèi)部類對象時,一定要先創(chuàng)建起相應(yīng)的外部類對象。至于原因,也就引出了我們下一個話題??
      * 非靜態(tài)內(nèi)部類對象有著指向其外部類對象的引用
      對剛才的例子稍作修改:
    public class Goods {
    private valueRate=2;
    private class Content implements Contents {
    private int i = 11 * valueRate;
    public int value() {
    return i;
    }
    }
    protected class GDestination implements Destination {
    private String label;
    private GDestination(String whereTo) {
    label = whereTo;
    }
    public String readLabel() {
    return label;
    }
    }
    public Destination dest(String s) {
    return new GDestination(s);
    }
    public Contents cont() {
    return new Content();
    }
    }
      修改的部分用藍(lán)色顯示了。在這里我們給 Goods 類增加了一個 private 成員變量 valueRate,意義是貨物的價值系數(shù),在內(nèi)部類 Content 的方法 value() 計(jì)算價值時把它乘上。我們發(fā)現(xiàn),value() 可以訪問 valueRate,這也是內(nèi)部類的第二個好處??一個內(nèi)部類對象可以訪問創(chuàng)建它的外部類對象的內(nèi)容,甚至包括私有變量!這是一個非常有用的特性,為我們在設(shè)計(jì)時提供了更多的思路和捷徑。要想實(shí)現(xiàn)這個功能,內(nèi)部類對象就必須有指向外部類對象的引用。Java 編譯器在創(chuàng)建內(nèi)部類對象時,隱式的把其外部類對象的引用也傳了進(jìn)去并一直保存著。這樣就使得內(nèi)部類對象始終可以訪問其外部類對象,同時這也是為什么在外部類作用范圍之外向要創(chuàng)建內(nèi)部類對象必須先創(chuàng)建其外部類對象的原因。
      有人會問,如果內(nèi)部類里的一個成員變量與外部類的一個成員變量同名,也即外部類的同名成員變量被屏蔽了,怎么辦?沒事,Java里用如下格式表達(dá)外部類的引用:
      outerClass.this
      有了它,我們就不怕這種屏蔽的情況了。
      * 靜態(tài)內(nèi)部類
      和普通的類一樣,內(nèi)部類也可以有靜態(tài)的。不過和非靜態(tài)內(nèi)部類相比,區(qū)別就在于靜態(tài)內(nèi)部類沒有了指向外部的引用。這實(shí)際上和 C++ 中的嵌套類很相像了,Java 內(nèi)部類與 C++ 嵌套類最大的不同就在于是否有指向外部的引用這一點(diǎn)上,當(dāng)然從設(shè)計(jì)的角度以及以它一些細(xì)節(jié)來講還有區(qū)別。
      除此之外,在任何非靜態(tài)內(nèi)部類中,都不能有靜態(tài)數(shù)據(jù),靜態(tài)方法或者又一個靜態(tài)內(nèi)部類(內(nèi)部類的嵌套可以不止一層)。不過靜態(tài)內(nèi)部類中卻可以擁有這一切。這也算是兩者的第二個區(qū)別吧。
      * 局部內(nèi)部類
      是的,Java 內(nèi)部類也可以是局部的,它可以定義在一個方法甚至一個代碼塊之內(nèi)。
    public class Goods1 {
    public Destination dest(String s) {
    class GDestination implements Destination {
    private String label;
    private GDestination(String whereTo) {
    label = whereTo;
    }
    public String readLabel() { return label; }
    }
    return new GDestination(s);
    }
    public static void main(String[] args) {
    Goods1 g= new Goods1();
    Destination d = g.dest("Beijing");
    }
    }
      上面就是這樣一個例子。在方法dest中我們定義了一個內(nèi)部類,最后由這個方法返回這個內(nèi)部類的對象。如果我們在用一個內(nèi)部類的時候僅需要創(chuàng)建它的一個對象并創(chuàng)給外部,就可以這樣做。當(dāng)然,定義在方法中的內(nèi)部類可以使設(shè)計(jì)多樣化,用途絕不僅僅在這一點(diǎn)。


      下面有一個更怪的例子:
    public class Goods2{
    private void internalTracking(boolean b) {
    if(b) {
    class TrackingSlip {
    private String id;
    TrackingSlip(String s) {
    id = s;
    }
    String getSlip() { return id; }
    }
    TrackingSlip ts = new TrackingSlip("slip");
    String s = ts.getSlip();
    }
    }
    public void track() { internalTracking(true); }
    public static void main(String[] args) {
    Goods2 g= new Goods2();
    g.track();
    }
    }
      你不能在 if 之外創(chuàng)建這個內(nèi)部類的對象,因?yàn)檫@已經(jīng)超出了它的作用域。不過在編譯的時候,內(nèi)部類 TrackingSlip 和其他類一樣同時被編譯,只不過它由它自己的作用域,超出了這個范圍就無效,除此之外它和其他內(nèi)部類并沒有區(qū)別。
      2.匿名類
      匿名類是不能有名稱的類,所以沒辦法引用他們。必須在創(chuàng)建時,作為new語句的一部分來聲明他們。
      這就要采用另一種形式的new語句,如下所示:
      new <類或接口> <類的主體>
      這種形式的new語句聲明一個新的匿名類,他對一個給定的類進(jìn)行擴(kuò)展,或?qū)崿F(xiàn)一個給定的接口。他還創(chuàng)建那個類的一個新實(shí)例,并把他作為語句的結(jié)果而返回。要擴(kuò)展的類和要實(shí)現(xiàn)的接口是new語句的操作數(shù),后跟匿名類的主體。
      假如匿名類對另一個類進(jìn)行擴(kuò)展,他的主體能夠訪問類的成員、覆蓋他的方法等等,這和其他任何標(biāo)準(zhǔn)的類都是相同的。假如匿名類實(shí)現(xiàn)了一個接口,他的主體必須實(shí)現(xiàn)接口的方法。
      注意匿名類的聲明是在編譯時進(jìn)行的,實(shí)例化在運(yùn)行時進(jìn)行。這意味著for循環(huán)中的一個new語句會創(chuàng)建相同匿名類的幾個實(shí)例,而不是創(chuàng)建幾個不同匿名類的一個實(shí)例。
      從技術(shù)上說,匿名類可被視為非靜態(tài)的內(nèi)部類,所以他們具備和方法內(nèi)部聲明的非靜態(tài)內(nèi)部類相同的權(quán)限和限制。
      假如要執(zhí)行的任務(wù)需要一個對象,但卻不值得創(chuàng)建全新的對象(原因可能是所需的類過于簡單,或是由于他只在一個方法內(nèi)部使用),匿名類就顯得很有用。匿名類尤其適合在Swing應(yīng)用程式中快速創(chuàng)建事件處理程式。
    interface pr {
    void print1();
    }
    public class noNameClass {
    public pr dest() {
    return new pr() {
    public void print1() {
    System.out.println("Hello world!!");
    }
    };
    }
    }
    public static void main(String args[]) {
    noNameClass c = new noNameClass();
    pr hw = c.dest();
    hw.print1();
    }
      pr 也可以是一個類,但是你外部調(diào)用的方法必須在你的這個類或接口中聲明,外部不能調(diào)用匿名類內(nèi)部的方法。
     Java 中內(nèi)部匿名類用的最多的地方也許就是在 Frame 中加入 Listner 了吧。
    import java.awt.*;
    import java.awt.event.*;
    public class QFrame extends Frame {
    public QFrame() {
    this.setTitle(\"my application\");
    addWindowListener(new WindowAdapter() {
    public void windowClosing(WindowEvent e) {
    dispose();
    System.exit(0);
    }
    });
    this.setBounds(10,10,200,200);
    }
    }
      內(nèi)部匿名類,就是建立一個內(nèi)部的類,但沒有給你命名,也就是沒有引用實(shí)例的變量。
    new WindowAdapter() {
    public void windowClosing(WindowEvent e) {
    dispose();
    System.exit(0);
    }
    }
      new 是建立一個 WindowAdapter 對象,后面一個 {} 表示這個括號中的操作作用于這個默認(rèn)的對名象,而上面的 Java 程序中后面是一個函數(shù)體。
      這個用法的作用是:創(chuàng)建一個對象的實(shí)例,并且 override 它的一個函數(shù)。
      打開 WindowAdapter 的代碼可以發(fā)現(xiàn)。它是一個抽象類。它是對 WindowListener 接口的一個實(shí)現(xiàn)。
      Frame.addWindowListner(); 的參數(shù)是一個 WindowListner ,而實(shí)現(xiàn)上是傳一個從WindowAdapter 派生出的一個匿名類。
      有一點(diǎn)需要注意的是,匿名內(nèi)部類由于沒有名字,所以它沒有構(gòu)造函數(shù)(但是如果這個匿名內(nèi)部類繼承了一個只含有帶參數(shù)構(gòu)造函數(shù)的父類,創(chuàng)建它的時候必須帶上這些參數(shù),并在實(shí)現(xiàn)的過程中使用 super 關(guān)鍵字調(diào)用相應(yīng)的內(nèi)容)。如果你想要初始化它的成員變量,有下面幾種方法:
      1. 如果是在一個方法的匿名內(nèi)部類,可以利用這個方法傳進(jìn)你想要的參數(shù),不過記住,這些參數(shù)必須被聲明為 final 。
      2. 將匿名內(nèi)部類改造成有名字的局部內(nèi)部類,這樣它就可以擁有構(gòu)造函數(shù)了。
      3. 在這個匿名內(nèi)部類中使用初始化代碼塊。

    posted on 2013-12-17 09:14 順其自然EVO 閱讀(263) 評論(0)  編輯  收藏


    只有注冊用戶登錄后才能發(fā)表評論。


    網(wǎng)站導(dǎo)航:
     
    <2013年12月>
    24252627282930
    1234567
    891011121314
    15161718192021
    22232425262728
    2930311234

    導(dǎo)航

    統(tǒng)計(jì)

    常用鏈接

    留言簿(55)

    隨筆分類

    隨筆檔案

    文章分類

    文章檔案

    搜索

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 好大好硬好爽免费视频| 成年女人午夜毛片免费视频| 亚洲AV无码一区二区三区国产 | 国产亚洲精彩视频| 国产免费卡一卡三卡乱码| 亚洲国产精品无码观看久久| 韩国欧洲一级毛片免费| 日韩色日韩视频亚洲网站| 亚洲国产成人爱av在线播放| 一级毛片一级毛片免费毛片| 亚洲色精品aⅴ一区区三区| 无码av免费网站| 亚洲三级中文字幕| 国产视频精品免费| 一日本道a高清免费播放| 国产AV无码专区亚洲精品| 一级成人a毛片免费播放| 亚洲香蕉在线观看| 免费在线观看污网站| 中文日本免费高清| 亚洲免费闲人蜜桃| 国产成人在线观看免费网站 | 亚洲AV日韩AV高潮无码专区| 99精品在线免费观看| 国产成人精品日本亚洲网址| 国产一级淫片免费播放电影| 91av免费在线视频| 亚洲欧洲日产v特级毛片| 成人免费视频国产| 久操免费在线观看| 亚洲日本VA中文字幕久久道具| 亚洲国产高清精品线久久| 久9热免费精品视频在线观看| 中文字幕亚洲综合久久综合| 亚洲精品无码AV中文字幕电影网站 | 免费观看又污又黄在线观看| 亚洲AV无一区二区三区久久| 性感美女视频免费网站午夜| 中文成人久久久久影院免费观看 | 亚洲免费视频一区二区三区| 在线电影你懂的亚洲|