Java 內部類、成員類、局部類、匿名類等

Java各種稱呼類詳解

  Java有各種各樣類,內部類、嵌套類、成員類、局部類(本地類)、靜態類、匿名類、文件類以及這些組合起來的稱呼類,成員內部類,成員匿名類,成員嵌套類,本地匿名類等,真是多的不行,但有些其實是一個意思,在這裏好好理一理。

聲明

  1.注意,這些稱呼都是翻譯過來的,但是同一個英文單詞或一個詞組翻譯過來可能有不同叫法,比如local nested class,local有局部、本地意思,其實是一個意思,local nested class翻譯過來就是局部嵌套類(本地嵌套類),又因爲非靜態嵌套類都稱爲內部類,所以local nested class又叫爲內部局部類(本地內部類),最終又簡稱爲:局部類(本地類)。我個人覺得局部類更加形象點所以下面都優先採用局部類一說。
  2.我通過搜索找到兩種不太相同的內部類定義,一種認爲:定義在類裏面的稱爲嵌套類(nested class),而非靜態嵌套類纔是內部類(inner class),也就是說嵌套類包含內部類;另外一種則是認爲:定義在類裏面的稱爲內部類,這樣靜態嵌套類也是內部類,也就是說嵌套類=內部類。但是,第一種纔是Java語言規範規定的,我一開始不確定,找到Java7的語言規範驗證,結果確實如此,即第一種纔是正確的,那麼問題來了:依照第一種劃分,靜態內部類其實是一種錯誤說法。。。只有靜態嵌套類,內部類是沒有靜態一說的!
  但是對於大多數中國程序員,貌似將定義在類裏面的類稱爲內部類不是更符合文意麼?也許這就是爲什麼會有這麼多人一直認爲靜態內部類的存在。嘛,反正不管怎麼稱呼,只要知道代表什麼意思就好,細節什麼的不要在意(光哥:所以不注意細節的你寫的代碼才這麼一大堆bug麼?還不趕緊去改(怒吼))。
  我這裏採用Java語言規範上說的。

0.文件類

  文件類放在最前面,是因爲文件類是與主類(一個文件中public類)關係最不密切的一類。什麼是文件類?看代碼就知道:

public class Main{}
class Test{}//Test就是文件類
//是的,一個.java文件裏面定義在主類外面的就是文件類
//主類、文件類稱爲頂級類(top level class),Java語言規範中定義:非嵌套類即爲頂級類。

【注意】:主類這一定義是我自己按語義稱呼的,有的地方稱爲基本類,但我覺得很不符合語義,Java語言規範我也沒找到相關定義。

  1. 因爲一個.java文件只能有一個主類(public 類),所以文件類默認只能是包訪問權限,即:不是同一個包的是無法引入和使用的。

1.嵌套類

  由上面文件類可有類似定義:一個.java文件裏面定義在類裏面的就是嵌套類,定義在類內部,包括塊、靜態塊、構造器、方法內。這個時候該類也相對來被稱爲包裝類(enclosing class)或外部類。
  嵌套類是可以有層次的,也就是說嵌套類裏面還可以定義類,成爲嵌套類中的嵌套類。
  在Java語言規範裏面,嵌套類定義是:

A nested class is any class whose declaration occurs within the body of 
another class or interface. 

  說的簡單一點,就是定義在類(這裏還包括接口,下同)裏面的類。所以說,以下所有的類都可以稱爲嵌套類。嵌套類分爲兩種:靜態嵌套類和非靜態嵌套類,非靜態嵌套類就是內部類(inner class)。

靜態嵌套類

  簡稱靜態類,和主類關係也不大,只是在其他類中引用使用的時候需要加上外部類限定,但在技術上來看,完全是兩個獨立無關係的類。

public class Main{
    public static class NestClass{}
}
//在外面使用時候形式如下,在Main中使用則不需要加上外部類限定
Main.NestClass nestClass = new Main.NestClass();

  從形式上來看,靜態類可以說是類的一個靜態成員(所以也可以說是成員類一種),但從技術上來看,其實二者沒什麼關係,可以看做第三類頂級類。但也因此,靜態類不怎麼常用,因爲它同一般類沒什麼優勢可言。

  1. 靜態類不能訪問外部類的非靜態成員和非靜態方法(不管是public還是private的);
  2. 靜態類的實例不需要先實例化外部類成員,可直接實例化。

2.內部類

  Java語言規範裏的定義:

An inner class is a nested class that is not explicitly or implicitly 
declared static.
//即非靜態嵌套類即爲內部類

內部類包括:成員類、局部類、匿名類。

  1. 內部類中不能有靜態修飾的成員(比如塊、字段、方法、接口等),總之不能有static關鍵字,除了一種情況,那就是靜態常量,又因爲常量成員字段必須在聲明的時候初始化,所以形式只能如:public static final int a = 6;
  2. 內部類可以訪問外部類任何成員,不管是公有的還是私有的,靜態的還是非靜態的(並且內部類的成員的名字也可以同外部相同,只不過這樣會覆蓋掉去外部類的),這是因爲每一個內部類都保存了一個對外部類的一個引用。這很好理解,因爲你要實例化這個內部類,肯定是通過外部類的一個實例,而內部類保留的這個引用就是這個外部類實例。
  3. 內部類命名格式:外部類名稱+$+[該種類同名類中該類順序]+[內部類名稱],例如成員類,成員類不能同名,所以也就沒有同名類順序:com.fcc.test.OuterClass$MemberClass;局部類:com.fcc.test.OuterClass$1LocalClass;匿名類:匿名類沒有名稱,所以格式如:com.fcc.OuterClass$1。

成員類

  這裏說的是非靜態成員內部類(如果靜態嵌套類也算是成員類一種的話),non-static member (inner) class。而一般說的也是這種,但從技術上來看,成員類應該還包括靜態嵌套類。

A member class is a class whose declaration is directly enclosed in 
another class or interface declaration.

  成員類算是最常見最常用的一種內部類,我們一般說的內部類說的就是成員類:在類裏面,但不在塊、構造器、方法裏面。

//成員類,從技術上來說,可以分爲兩種:成員內部類和成員嵌套類。
//1.成員內部類即這裏說的成員類,全稱是非靜態成員內部類
//2.成員嵌套類即上面的靜態嵌套類
public class Main{
    public class MemberClass{}//成員內部類,常簡稱爲成員類
}

  成員類,可以使用public,private,protected訪問控制符,也可以用static,final關鍵字修飾,並且有enclose class屬性。
這裏題外說明一下:

  1. 成員(member),只要是在類裏面的(但不在塊、構造器、方法內),都是成員:可以是變量,就是成員變量(一般又稱爲成員字段,Field);可以是方法,好吧,方法都是成員(因爲Java中方法不可能位於類外)的;當然,同樣的,也可以是接口、枚舉、註釋類以及類。
  2. 關於static理解,有static修飾的是類本身屬性(共性),所以訪問可以不通過類的實例對象,而非static修飾的,是對象屬性(個性),必須通過類的實例對象訪問,因爲個性是個體的屬性啊,當然要創建出個體,然後這個個性纔有意義。
  3. 關於enclose class,enclose method,enclose constructor屬性,可以理解爲這個類是被類、還是方法、構造器包裝起來的。關於這些屬性,可以參考Class類:Java源碼解析(2) —— Class(1)

局部類(本地類)

  local nested class,局部嵌套類,簡稱局部類,局部類所屬範圍:在塊、構造器以及方法內,這裏的塊包括普通塊和靜態塊。局部類只在本塊範圍內有效。
定義:

A local class is a nested class8) that is not a member of any class 
and that has a name.

翻譯過來就是:局部類是嵌套類,但不是成員類,而且有名稱(不是匿名類)。

public class Test {
    {
        class AA{}//塊內局部類
    }
    public Test(){
        class AA{}//構造器內局部類
    }
    public static void main(String[] args){
    }
    public void test(){
        class AA{}//方法內局部類
    }
}
//注意到了吧,可以同名,編譯後,形成諸如:外部類名稱+$+同名順序+局部類名稱
//Test$1AA.class/Test$2AA.class/Test$3AA.class

  局部類最多只能有final修飾,但不同的是,塊內局部類有enclose class屬性,而構造器局部類有enclose constructor屬性,方法局部類有enclose method屬性,嘛,其實很好理解的吧,一看就知道。

  1. 局部類只能訪問(使用)這個塊中(局部類外)final屬性。這裏的塊包括了上面說的塊、構造器、方法。

匿名類

定義:

An anonymous class declaration is automatically derived from a class 
instance creation expression by the Java compiler

  匿名類,就是沒有名稱的類,其名稱由Java編譯器給出,一般是形如:外部類名稱+$+匿名類順序,沒有名稱也就是其他地方就不能引用,不能實例化,只用一次,當然也就不能有構造器。
  匿名類根據位於地方不同分爲:成員匿名類和局部匿名類。

public class Test {
    InterfaceA a = new InterfaceA() {};//成員匿名類
    public static void main(String[] args){
        InterfaceA a = new InterfaceA() {};//局部匿名類
        //以上兩種是通過實現接口實現匿名類,稱爲接口式匿名類,也可以通過繼承類
        Test test = new Test(){};//繼承式匿名類
        //還可以是位於參數上
        new Thread(new Runnable() {
            @Override
            public void run() {
            }
        }).start();//屬於局部匿名類一種
    }
    private interface InterfaceA{}
}

  匿名類不能使用任何關鍵字和訪問控制符,匿名類和局部類訪問規則一樣,只不過內部類顯式的定義了一個類,然後通過new的方式創建這個局部類實例,而匿名類直接new一個類實例,沒有定義這個類。匿名類最常見的方式就是回調模式的使用,通過默認實現一個接口創建一個匿名類然後,然後new這個匿名類的實例。

總結

  本文討論的是:嵌套類、內部類、成員類、局部類、匿名類相關,這些類的劃分主要是根據類聲明(或位於)的地方劃分的:
1.嵌套類,位於類內部,又分爲:靜態嵌套類和非靜態嵌套類。
2.靜態嵌套類即爲靜態類。靜態類只有這一種,技術來說,也可以看成靜態成員類。
3.非靜態嵌套類即爲內部類,又分爲:成員類、局部類(本地類)、匿名類。
4.成員類:位於類內部但不包括位於塊、構造器、方法內,且有名稱的類。
5.局部類:位於塊、構造器、方法內的有名稱類。
6.匿名類:類內無名稱類,又可細分爲:成員匿名類和局部匿名類。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章