天天看點

Java的這些細小知識,你都知道嗎?——類與對象Java語言基本元素

目錄

  • Java語言基本元素
    • 類和對象
      • 概念
        • 圖示屬性和行為
        • 圖示類成員的構成(完成版)
        • 類的文法格式
          • 如何建立Java自定義類
      • 對象
        • 對象的建立和使用
            • 建立
            • 使用
            • 注意
        • 對象的記憶體解析
          • 對象的産生
          • 對象的生命周期
          • 記憶體解析
            • 記憶體解析相關概念
            • 記憶體解析執行個體
        • 匿名對象
          • 什麼情況下使用匿名對象?
    • 類的成員
      • 屬性(變量)
        • 文法格式
          • 說明1:修飾符
          • 說明2:資料類型
          • 說明3:屬性名
        • 變量的分類
          • 圖示變量的分類
        • 成員變量(屬性)和局部變量的差別?
            • 解析
        • 變量的預設初始化指派
        • 屬性指派的先後順序
      • 方法
        • 什麼是方法(method、函數)
        • 方法的聲明格式
            • 注意:
          • return關鍵字的使用:
          • 如何了解方法傳回值類型為void的情況 ?
        • 方法的分類
        • 方法的調用
          • 方法調用的過程分析
          • 注意事項
        • 方法的重載
          • 概念
          • 特點
            • "兩同一不同":
          • 示例
          • 判斷是否為重載
        • 方法的重寫
          • 要求:
          • 注意:
          • 示例
            • 分析
        • 再談方法的重載與重寫
        • 方法中可變個數的形參
          • 注意事項
        • 方法參數的值傳遞機制
          • Java的實參值如何傳入方法呢?
          • 參數傳遞解析
            • 基本資料類型的參數傳遞
            • 引用資料類型的參數傳遞
          • 遞歸方法
        • main方法
          • main方法的特點
            • 指令行參數用法舉例
          • 了解main方法的文法
      • 構造器(構造方法)
          • 構造器的特征
          • 構造器的作用
          • 文法格式
          • 構造器的分類
          • 構造器的注意事項
          • 構造器重載
      • 代碼塊
          • 代碼塊的作用
          • 代碼塊的分類
          • 靜态代碼塊 vs 非靜态代碼塊
            • 靜态代碼塊:用static 修飾的代碼塊
            • 非靜态代碼塊:沒有static修飾的代碼塊
        • 使用示例
      • 内部類
        • 什麼情況下使用内部類?
        • 内部類分類
          • 成員内部類(靜态、非靜态)
          • 局部内部類(方法内、代碼塊内、構造器内)
            • 如何聲明内部類?
            • 如何使用局部内部類
            • 局部内部類的特點
          • 匿名内部類
            • 格式:
            • 匿名内部類的特點
        • 注意事項
        • 使用示例

Java語言基本元素

類和對象

概念

  1. 類(Class)和對象(Object)是面向對象的核心概念。
    類是對一類事物的描述,是抽象的、概念上的定義
    對象是實際存在的該類事物的每個個體,因而也稱為執行個體(instance)。
  2. “萬事萬物皆對象”

Field = 屬性 = 成員變量

Method = (成員)方法 = 函數

建立類的對象 = 類的執行個體化 = 執行個體化類

現實世界的生物體,大到鲸魚,小到螞蟻,都是由最基本的細胞構成的。同理, Java代碼世界是由諸多個不同功能的類構成的。

現實生物世界中的細胞又是由什麼構成的呢?細胞核、細胞質、 … 那麼,Java中用類class來描述事物也是如此。常見的類的成員有:

  • 屬 性:對應類中的成員變量
  • 行 為:對應類中的成員方法

圖示屬性和行為

Java的這些細小知識,你都知道嗎?——類與對象Java語言基本元素
Java的這些細小知識,你都知道嗎?——類與對象Java語言基本元素

圖示類成員的構成(完成版)

Java的這些細小知識,你都知道嗎?——類與對象Java語言基本元素

類的文法格式

修飾符 class 類名 {
    屬性聲明;
    方法聲明;
}
           

說明: 修飾符public:類可以被任意通路

類的正文要用{ }括起來

舉例:

public class Person{
	private int age ; //聲明私有變量 age
	public void showAge(int i) { //聲明方法showAge( )
		age = i;
	}
}
           
如何建立Java自定義類
  1. 定義類(考慮修飾符、類名)
  2. 編寫類的屬性(考慮修飾符、屬性類型、屬性名、 初始化值)
  3. 編寫類的方法(考慮修飾符、傳回值類型、方法名、形參等)

對象

對象的建立和使用

建立

類名 對象名 = new 類名();

使用

通路對象成員(包括屬性和方法)

對象名.對象成員

注意

如果建立了一個類的多個對象,則每個對象都獨立的擁有一套類的屬性。(非static的)

  • 意味着:如果我們修改一個對象的屬性a,則不影響另外一個對象屬性a的值。

對象的記憶體解析

對象的産生

Person p1=new Person();

Java的這些細小知識,你都知道嗎?——類與對象Java語言基本元素
對象的生命周期

類對象的指派相當于指派的是引用(儲存對象的位址)

Person p1=new Person(); Person p2=p1;

Java的這些細小知識,你都知道嗎?——類與對象Java語言基本元素
Java的這些細小知識,你都知道嗎?——類與對象Java語言基本元素
Java的這些細小知識,你都知道嗎?——類與對象Java語言基本元素
記憶體解析
Java的這些細小知識,你都知道嗎?——類與對象Java語言基本元素

記憶體解析相關概念

堆(Heap) , 此記憶體區域的唯一目的就是存放對象執行個體, 幾乎所有的對象執行個體都在這裡配置設定記憶體。 這一點在Java虛拟機規範中的描述是:所有的對象執行個體以及數組都要在堆上配置設定。
通常所說的棧(Stack) , 是指虛拟機棧。 虛拟機棧用于存儲局部變量等。局部變量表存放了編譯期可知長度的各種基本資料類型(boolean、 byte、char 、 short 、 int 、 float 、 long 、double) 、 對象引用(reference類型,它不等同于對象本身, 是對象在堆記憶體的首位址) 。 方法執行完, 自動釋放。
方法區(Method Area) , 用于存儲已被虛拟機加載的類資訊、 常量、 靜态變量、 即時編譯器編譯後的代碼等資料。

記憶體解析執行個體

Java的這些細小知識,你都知道嗎?——類與對象Java語言基本元素

匿名對象

不定義對象的句柄,而直接調用這個對象的方法。這樣的對象叫做匿名對象。

例如:

new Person().shout();

什麼情況下使用匿名對象?
  1. 如果對一個對象隻需要進行一次方法調用,那麼就可以使用匿名對象。
  2. 我們經常将匿名對象作為實參傳遞給一個方法調用。

類的成員

屬性(變量)

文法格式

修飾符 資料類型 屬性名 = 初始化值 ;

說明1:修飾符
  1. 常用的權限修飾符有: private、預設、 protected、 public
  2. 其他修飾符: static、 final (暫不考慮)
說明2:資料類型

任何基本資料類型(如int、 Boolean) 或 任何引用資料類型。

說明3:屬性名

屬于辨別符,符合命名規則和規範即可

變量的分類

成員變量:在方法體外,類體内聲明的變量稱為成員變量。
局部變量:在方法體内部聲明的變量稱為局部變量。
圖示變量的分類
Java的這些細小知識,你都知道嗎?——類與對象Java語言基本元素

成員變量(屬性)和局部變量的差別?

成員變量 局部變量
聲明的位置 直接聲明在類中 方法形參或内部、代碼塊内、構造器内等
修飾符 private、 public、 static、 final等 不能用權限修飾符修飾,可以用final修飾
初始化值 有預設初始化值 沒有預設初始化值,必須顯式指派,方可使用
記憶體加載位置 堆空間 或 靜态域内 棧 棧空間

解析

1.相同點:

​ 1.1 定義變量的格式:

資料類型 變量名 = 變量值

​ 1.2 先聲明,後使用

​ 1.3 變量都有其對應的作用域

2.不同點:

​ 2.1 在類中聲明的位置的不同

  • 成員變量:直接定義在類的一對{}内
  • 局部變量:聲明在方法内、方法形參、代碼塊内、構造器形參、構造器内部的變量

​ 2.2 關于權限修飾符的不同

  • 成員變量:可以在聲明屬性時,指明其權限,使用權限修飾符。
  • 常用的權限修飾符:private、public、預設、protected —>封裝性
  • 目前,大家聲明屬性時,都使用預設就可以了。
  • 局部變量:不可以使用權限修飾符。

​ 2.3 預設初始化值的情況:

  • 成員變量:類的屬性,根據其類型,都有預設初始化值。- 預設初始化指派表
  • 局部變量:沒有預設初始化值。意味着,我們在調用局部變量之前,一定要顯式指派。
  • 特别地:形參在調用時,我們指派即可。

2.4 在記憶體中加載的位置:

  • 成員變量:加載到堆空間中 (非static)
  • 局部變量:加載到棧空間

變量的預設初始化指派

當一個對象被建立時,會對其中各種類型的成員變量自動進行初始化指派。除了

基本資料類型之外的變量類型都是引用類型,如上面的Person及前面講過的數組。

成員變量類型 初始值
byte
short
int
long 0L
float 0.0F
double 0.0
char 0 或寫為:’\u0000’(表現為空)
boolean false
引用類型 null

屬性指派的先後順序

① 預設初始化

② 顯式初始化

③ 構造器中初始化

④ 通過"對象.方法" 或 "對象.屬性"的方式,指派

⑤在代碼塊中指派

以上操作的先後順序:① - ②/⑤(根據先後順序判斷) - ③ - ④

方法

什麼是方法(method、函數)

  1. 方法是類或對象行為特征的抽象,用來完成某個功能操作(描述類應該具有的功能)。在某些語言中也稱為函數或過程。
  2. 将功能封裝為方法的目的是,可以實作代碼重用,簡化代碼
  3. Java裡的方法不能獨立存在,所有的方法必須定義在類裡。

方法的聲明格式

修飾符 傳回值類型 方法名(參數類型 形參1, 參數類型 形參2, ….){
	方法體程式代碼
	return 傳回值;
}
           

注意:

  1. 修飾符: public,預設,private, protected等
  2. 傳回值類型:
  • 沒有傳回值: void。
  • 有傳回值,聲明出傳回值的類型。與方法體中“return 傳回值” 搭配使用
  1. 方法名:屬于辨別符,命名時遵循辨別符命名規則和規範,“見名知意”

    形參清單:可以包含零個,一個或多個參數。多個參數時,中間用“,”隔開

    傳回值:方法在執行完畢後返還給調用它的程式的資料。

  2. 方法中,不可以定義方法。
  3. 特殊的:方法A中又調用了方法A:遞歸方法。
return關鍵字的使用:

使用範圍:使用在方法體中

作用:① 結束方法

② 針對于有傳回值類型的方法,使用"return 資料"方法傳回所要的資料。

注意點:return關鍵字後面不可以聲明執行語句。

如何了解方法傳回值類型為void的情況 ?

傳回值類型: 有傳回值 vs 沒有傳回值

  • 如果方法有傳回值,則必須在方法聲明時,指定傳回值的類型。同時,方法中,需要使用return關鍵字來傳回指定類型的變量或常量:“return 資料”。
  • 如果方法沒有傳回值,則方法聲明時,使用void來表示。通常,沒有傳回值的方法中,就不需要使用return.但是,如果使用的話,隻能“return;”表示結束此方法的意思。

方法的分類

分類 有傳回值 無傳回值
無形參 void 方法名(){} 傳回值的類型 方法名(){}
有形參 有形參 void 方法名(形參清單){} 傳回值的類型 方法名(形參清單){}

方法的調用

方法通過方法名被調用,且隻有被調用才會執行。

方法調用的過程分析
Java的這些細小知識,你都知道嗎?——類與對象Java語言基本元素
注意事項
  1. 方法被調用一次,就會執行一次
  2. 沒有具體傳回值的情況,傳回值類型用關鍵字void表示,那麼方法體中可以不必使用return語句。如果使用,僅用來結束方法。
  3. 定義方法時,方法的結果應該傳回給調用者,交由調用者處理。
  4. 方法中隻能調用方法或屬性, 不可以在方法内部定義方法。

方法的重載

概念
重載:在同一個類中,允許存在一個以上的同名方法,隻要它們的參數個數或者參數類型不同即可。
特點

與傳回值類型無關,隻看參數清單,且參數清單必須不同。 (參數個數或參數類型)。調用時,根據方法參數清單的不同來差別。

“兩同一不同”:

  • 同一個類、相同方法名
  • 參數清單不同:參數個數不同,參數類型不同
               
示例
//傳回兩個整數的和
int add(int x,int y){return x+y;}
//傳回三個整數的和
int add(int x,int y,int z){return x+y+z;}
//傳回兩個小數的和
double add(double x,double y){return x+y;}
           
判斷是否為重載

跟方法的權限修飾符、傳回值類型、形參變量名、方法體都沒有關系!

方法的重寫

主要用于繼承。繼承

在子類中可以根據需要對從父類中繼承來的方法進行改造, 也稱為方法的重置、覆寫。在程式執行時,子類的方法将覆寫父類的方法。
要求:
  1. 子類重寫的方法必須和父類被重寫的方法具有相同的方法名稱、 參數清單
  2. 傳回值類型:
    • 父類被重寫的方法的傳回值類型是void,則子類重寫的方法的傳回值類型隻能是void
    • 父類被重寫的方法的傳回值類型是A類型,則子類重寫的方法的傳回值類型可以是A類或A類的子類
    • 父類被重寫的方法的傳回值類型是基本資料類型(比如:double),則子類重寫的方法的傳回值類型必須是相同的基本資料類型(必須也是double)
  3. 子類重寫的方法使用的通路權限不能小于父類被重寫的方法的通路權限
  • 子類不能重寫父類中聲明為private權限的方法
  1. 子類方法抛出的異常不能大于父類被重寫方法的異常
注意:

子類與父類中同名同參數的方法必須同時聲明為

非static

的(即為重寫),或者同時聲明為

static

的(不是重寫) 。因為static方法是屬于類的,子類無法覆寫父類的方法。

示例
public class Person { 
    public String name; 
    public int age;
    
    public String getInfo() {
    	return "Name: "+ name + "\n" +"age: "+ age;
    }
}

public class Student extends Person {
	public String school;
    
    public String getInfo() { //重寫方法
        return "Name: "+ name + "\nage: "+ age + "\nschool: "+ school;
    }
    public static void main(String args[]){
        Student s1=new Student();
        s1.name="Bob";
        s1.age=20;
        s1.school="school2";
        System.out.println(s1.getInfo()); //Name:Bob age:20 school:school2
    }
}
           

分析

Person p1=new Person();
//調用Person類的getInfo()方法
p1.getInfo();
Student s1=new Student();
//調用Student類的getInfo()方法
s1.getInfo();
           

這是一種“多态性”:同名的方法,用不同的對象來區分調用的是哪一個方法。

再談方法的重載與重寫

詳情見多态性的方法的重載與重寫 方法的重載與重寫與多态性(方法的重載是多态性的一種展現?NO)

方法中可變個數的形參

JavaSE 5.0 中提供了Varargs(variable number of arguments)機制,允許直接定義能和多個實參相比對的形參。進而,可以用一種更簡單的方式,來傳遞個數可變的實參。

//JDK 5.0以前: 采用數組形參來定義方法,傳入多個同一類型變量
public static void test(int a ,String[] books);

//JDK 5.0開始: 采用可變個數形參來定義方法,傳入多個同一類型變量
public static void test(int a ,String…books);
           
注意事項
  1. 聲明格式: 方法名(參數的類型名 …參數名)
  2. 可變參數:方法參數部分指定類型的參數個數是可變多個: 0個, 1個或多個
  3. 可變個數形參的方法與同名的方法之間,彼此構成重載
  4. 可變參數方法的使用與方法參數部分使用數組是一緻的
  5. 方法的參數部分有可變形參,需要放在形參聲明的最後
  6. 在一個方法的形參位置,最多隻能聲明一個可變個數形參

方法參數的值傳遞機制

形參:方法定義時,聲明的小括号内的參數
實參: 方法調用時,實際傳遞給形參的資料
Java的實參值如何傳入方法呢?

Java裡方法的參數傳遞方式隻有一種: 值傳遞。 即将實際參數值的副本(複制品)傳入方法内,而參數本身不受影響。

  • 形參是基本資料類型:将實參基本資料類型變量的“資料值”傳遞給形參
  • 形參是引用資料類型:将實參引用資料類型變量的“位址值”傳遞給形參
參數傳遞解析

基本資料類型的參數傳遞

形參不會修改堆空間實參的具體值,因為形參此時存儲的是實參的資料值

public static void main(String[] args) {
    int x = 5;
    System.out.println("修改之前x = " + x);// 5
    // x是實參
    change(x);
    System.out.println("修改之後x = " + x);// 5
}

public static void change(int x) {
    System.out.println("change:修改之前x = " + x);//5
    x = 3;
    System.out.println("change:修改之後x = " + x);//3
}
           
Java的這些細小知識,你都知道嗎?——類與對象Java語言基本元素

引用資料類型的參數傳遞

形參會修改堆空間實參的具體值,因為形參此時存儲的是實參的位址引用.

public static void main(String[] args) {
    Person obj = new Person();
    obj.age = 5;
    System.out.println("修改之前age = " + obj.age);// 5
    // x是實參
    change(obj);
    System.out.println("修改之後age = " + obj.age);// 3
}

public static void change(Person obj) {
    System.out.println("change:修改之前age = " + obj.age);//5
    obj.age = 3;
    System.out.println("change:修改之後age = " + obj.age);//3
}

//其中Person類定義為:
class Person{
	int age;
}
           
Java的這些細小知識,你都知道嗎?——類與對象Java語言基本元素
遞歸方法
遞歸方法:一個方法體内調用它自身。
  • 方法遞歸包含了一種隐式的循環,它會重複執行某段代碼,但這種重複執行無須循環控制。
  • 遞歸一定要向已知方向遞歸,否則這種遞歸就變成了無窮遞歸,類似于死循環。
//計算1-100之間所有自然數的和
public int sum(int num){
    if(num == 1){
    	return 1;
    }else{
    	return num + sum(num - 1);
    }
}
           

main方法

main方法的特點
  1. main()方法作為程式的入口
  2. main()方法也是一個普通的靜态方法
  3. main()方法可以作為我們與控制台互動的方式。(之前:使用Scanner)

    指令行參數用法舉例

    public class CommandPara {
        public static void main(String[] args) {
            for (int i = 0; i < args.length; i++) {
            	System.out.println("args[" + i + "] = " + args[i]);
            }
        }
    }
               
    //運作程式CommandPara.java

    java CommandPara “Tom" “Jerry" “Shkstart"

    輸出結果:

    輸出結果:

    args[0] = Tom
    args[1] = Jerry
    args[2] = Shkstart
               
了解main方法的文法
  1. 由于Java虛拟機需要調用類的main()方法,是以該方法的通路權限必須是public。又因為Java虛拟機在執行main()方法時不必建立對象,是以該方法必須是static的,該方法接收一個String類型的數組參數,該數組中儲存執行Java指令時傳遞給所運作的類的參數。
  2. 因為main() 方法是靜态的,我們不能直接通路該類中的非靜态成員,必須建立該類的一個執行個體對象後,才能通過這個對象去通路類中的非靜态成員。

構造器(構造方法)

構造器的特征
  1. 它具有與類相同的名稱
  2. 它不聲明傳回值類型。(與聲明為void不同)
  3. 不能被static、 final、 synchronized、 abstract、 native修飾,不能有return語句傳回值
構造器的作用

1. 建立對象;

2. 初始化對象的資訊

如:

Order o = new Order(); Person p = new Person(“Peter”,15);

如同我們規定每個“人”一出生就必須先洗澡,我們就可以在“人” 的構造器中加入完成“洗澡”的程式代碼,于是每個“人”一出生就會自動完成“洗澡”,程式就不必再在每個人剛出生時一個一個地告訴他們要“洗澡”了。

文法格式
修飾符 類名 (參數清單) {
	初始化語句;
}
           
構造器的分類

根據參數不同,構造器可以分為如下兩類:

  • 隐式無參構造器(系統預設提供)
  • 顯式定義一個或多個構造器(無參、有參)
構造器的注意事項
  1. Java語言中,每個類都至少有一個構造器
  2. 預設構造器的修飾符與所屬類的修飾符一緻
  3. 一旦顯式定義了構造器, 則系統不再提供預設構造器
  4. 一個類可以建立多個重載的構造器
  5. 父類的構造器不可被子類繼承
  6. 一個類中,至少會有一個構造器。
構造器重載

構造器重載,參數清單必須不同

構造器重載使得對象的建立更加靈活,友善建立各種不同的對象

構造器重載舉例:

public class Person{
    public Person(String name, int age, Date d) {this(name,age);…}
    public Person(String name, int age) {…}
    public Person(String name, Date d) {…}
    public Person(){…}
}
           

代碼塊

代碼塊的作用

用來初始化類、對象

代碼塊的分類

代碼塊如果有修飾的話,隻能使用static.

一個類中代碼塊若有修飾符, 則隻能被static修飾, 稱為靜态代碼塊(static block), 沒有使用static修飾的, 為非靜态代碼塊。
靜态代碼塊 vs 非靜态代碼塊

靜态代碼塊:用static 修飾的代碼塊

  1. 内部可以有輸出語句。
  2. 可以對類的屬性、類的聲明進行初始化操作。
  3. 不可以對非靜态的屬性初始化。即:不可以調用非靜态的屬性和方法。
  4. 若有多個靜态的代碼塊,那麼按照從上到下的順序依次執行。
  5. 靜态代碼塊的執行要先于非靜态代碼塊。
  6. 靜态代碼塊随着類的加載而加載,且隻執行一次。
  7. 作用:初始化類的資訊

非靜态代碼塊:沒有static修飾的代碼塊

  1. 内部可以有輸出語句。
  2. 可以對類的屬性、 類的聲明進行初始化操作。
  3. 非靜态代碼塊内可以調用靜态的屬性、靜态的方法,或非靜态的屬性、非靜态的方法
  4. 若有多個非靜态的代碼塊, 那麼按照從上到下的順序依次執行。
  5. 每次建立對象的時候, 都會執行一次(随着對象的建立而執行)。 且先于構造器執行。
  6. 作用:可以在建立對象時,對對象的屬性等進行初始化

使用示例

public class BlockTest {
   public static void main(String[] args) {
      
      String desc = Person.desc;
      System.out.println(desc);
      
      Person p1 = new Person();
      Person p2 = new Person();
      System.out.println(p1.age);
      
      Person.info();
   }
}


class Person{
   //屬性
   String name;
   
   int age;

   static String desc = "我是一個人";
   
   //構造器
   public Person(){}
    
   public Person(String name,int age){
      this.name = name;
      this.age = age;
   }
   
   //非static的代碼塊
   {
      System.out.println("hello, block - 2");
   }
   {
      System.out.println("hello, block - 1");
      //調用非靜态結構
      age = 1;
      eat();
      //調用靜态結構
      desc = "我是一個愛學習的人1";
      info();
   }
   //static的代碼塊
   static{
      System.out.println("hello,static block-2");
   }
   static{
      System.out.println("hello,static block-1");
      //調用靜态結構
      desc = "我是一個愛學習的人";
      info();
      //不可以調用非靜态結構
//    eat();
//    name = "Tom";
   }
   
   //方法
   public void eat(){
      System.out.println("吃飯");
   }
   @Override
   public String toString() {
      return "Person [name=" + name + ", age=" + age + "]";
   }
   public static void info(){
      System.out.println("我是一個快樂的人!");
   }
   
}
           

内部類

在Java中,允許一個類的定義位于另一個類的内部,前者稱為内部類,後者稱為外部類。

什麼情況下使用内部類?

當一個事物的内部,還有一個部分需要一個完整的結構進行描述,而這個内部的完整的結構又隻為外部事物提供服務,那麼整個内部的完整結構最好使用内部類。

内部類分類

成員内部類(靜态、非靜态)

一方面,作為外部類的成員:

  • 調用外部類的結構
               
  • 可以被static修飾, 但此時就不能再使用外層類的非static的成員變量
               
  • 可以被4種不同的權限修飾
               

另一方面,作為一個類:

  • 類内可以定義屬性、方法、構造器等
               
  • 可以被final修飾,表示此類不能被繼承。言外之意,不使用final,就可以被繼承
               
  • 可以被abstract修飾,是以可以被其它的内部類繼承
               
  • 編譯以後生成OuterClass$InnerClass.class位元組碼檔案(也适用于局部内部類)
局部内部類(方法内、代碼塊内、構造器内)

如何聲明内部類?

class 外部類{
    //方法中使用局部内部類
    方法(){
        class 局部内部類{
        }
    } 
    //代碼塊中使用局部内部類
    {
        class 局部内部類{
        }
    }
}
           

如何使用局部内部類

  1. 隻能在聲明它的方法或代碼塊中使用,而且是先聲明後使用。除此之外的任何地方都不能使用該類
  2. 但是它的對象可以通過外部方法的傳回值傳回使用,傳回值類型隻能是局部内部類的父類或父接口類型、
    public class InnerClassTest {
    	
    	//開發中很少見
    	public void method(){
    		//局部内部類
    		class AA{
    			
    		}
    	}
    	
    	//傳回一個實作了Comparable接口的類的對象
    	public Comparable getComparable(){
    		
    		//建立一個實作了Comparable接口的類:局部内部類
    		//方式一:
    //		class MyComparable implements Comparable{
    //
    //			@Override
    //			public int compareTo(Object o) {
    //				return 0;
    //			}
    //			
    //		}
    //		
    //		return new MyComparable();
    		
    		//方式二:
    		return new Comparable(){
    
    			@Override
    			public int compareTo(Object o) {
    				return 0;
    			}
    			
    		};
    		
    	}
    	
    }
               

局部内部類的特點

  1. 内部類仍然是一個獨立的類,在編譯之後内部類會被編譯成獨立的.class檔案,但是前面冠以外部類的類名和$符号,以及數字編号。
  2. 隻能在聲明它的方法或代碼塊中使用,而且是先聲明後使用。除此之外的任何地方都不能使用該類。
  3. 局部内部類可以使用外部類的成員,包括私有的。
  4. 局部内部類可以使用外部方法的局部變量,但是必須是final的。 由局部内部類和局部變量的聲明周期不同所緻。
  5. 局部内部類和局部變量地位類似,不能使用public,protected,預設,private
  6. 局部内部類不能使用static修飾,是以也不能包含靜态成員
匿名内部類
匿名内部類不能定義任何靜态成員、方法和類,隻能建立匿名内部類的一個執行個體。一個匿名内部類一定是在new的後面,用其隐含實作一個接口或實作一個類。

格式:

new 父類構造器(實參清單) |實作接口(){
//匿名内部類的類體部分
}
           

匿名内部類的特點

  1. 匿名内部類必須繼承父類或實作接口
  2. 匿名内部類隻能有一個對象
  3. 匿名内部類對象隻能使用多态形式引用

注意事項

  1. 非static的成員内部類中的成員不能聲明為static的, 隻有在外部類或static的成員内部類中才可聲明static成員。
  2. 外部類通路成員内部類的成員, 需要“内部類.成員”或“内部類對象.成員”的方式
  3. 成員内部類可以直接使用外部類的所有成員, 包括私有的資料
  4. 當想要在外部類的靜态成員部分使用内部類時, 可以考慮内部類聲明為靜态的

使用示例

public class InnerClassTest {
	public static void main(String[] args) {
		
		//建立Dog執行個體(靜态的成員内部類):
		Person.Dog dog = new Person.Dog();
		dog.show();
		//建立Bird執行個體(非靜态的成員内部類):
//		Person.Bird bird = new Person.Bird();//錯誤的
		Person p = new Person();
		Person.Bird bird = p.new Bird();
		bird.sing();
		
		System.out.println();
		
		bird.display("黃鹂");
		
	}
}


class Person{
	
	String name = "小明";
	int age;
	
	public void eat(){
		System.out.println("人:吃飯");
	}
	
	//靜态成員内部類
	static class Dog{
		String name;
		int age;
		
		public void show(){
			System.out.println("卡拉是條狗");
		}
		
	}
    
	//非靜态成員内部類
	class Bird{
		String name = "杜鵑";
		
		public Bird(){
			
		}
		
		public void sing(){
			System.out.println("我是一隻小小鳥");
			Person.this.eat();//調用外部類的非靜态屬性
			eat();
			System.out.println(age);
		}
		
		public void display(String name){
			System.out.println(name);//方法的形參
			System.out.println(this.name);//内部類的屬性
			System.out.println(Person.this.name);//外部類的屬性
		}
	}
	
	
	public void method(){
		//局部内部類
		class AA{}
	}
	
	{
		//局部内部類
		class BB{}
	}
	
	public Person(){
		//局部内部類
		class CC{}
	}
			
}