天天看點

【java】匿名類java 匿名類(匿名内部類)

java 匿名類(匿名内部類)

1. 初識 匿名類

标準說法: 内部類包括:成員類、局部類、匿名類(匿名内部類)。

匿名類概念:

  • 匿名類可以使你的代碼更加簡潔 (JDK8之後Lambda更簡潔)。
  • 你可以定義一個類的同時對其進行執行個體化。
  • 它與局部類很相似,不同的是它沒有類名,如果某個局部類你隻需要使用一次,就可以使用匿名類代替局部類。
  • 匿名類是表達式,而非正常的類

匿名類的使用場景:

  • 一個局部類隻需要使用一次的時候
  • 由于匿名類沒有類名,那麼除了定義它的地方,其他地方無法調用,是以匿名類也可以叫匿名内部類

2. 通過示例分析局部類和匿名類差別

sayHello

方法中有局部類和匿名類分别實作

HelloWorld

接口的方法

public class HelloWorldAnonymousClasses {

    interface HelloWorld {
        public void greet();
        public void greetSomeone(String someone);
    }

    public void sayHello() {

        /**
         * 1、局部類:EnglishGreeting實作了HelloWorld接口
         */
        class EnglishGreeting implements HelloWorld {
            String name = "無參";
            @Override
            public void greet() {
                greetSomeone(name);
            }
            @Override
            public void greetSomeone(String someone) {
                name = someone;
                System.out.println("局部類:" + name);
            }
        }
        // 建立局部類EnglishGreeting的執行個體化對象,使用接口類型接收
        HelloWorld englishGreeting = new EnglishGreeting();
        // 局部類:無參方法
        englishGreeting.greet();
        // 局部類:帶參方法
        englishGreeting.greetSomeone("帶參");


        /**
         * 2、匿名類實作HelloWorld接口并建立了執行個體化對象:frenchGreeting
         */
        HelloWorld frenchGreeting = new HelloWorld() {
            String name = "無參";
            @Override
            public void greet() {
                greetSomeone(name);
            }
            @Override
            public void greetSomeone(String someone) {
                name = someone;
                System.out.println("匿名類:" + name);
            }
        };

        // 匿名類:無參方法
        frenchGreeting.greet();
        // 匿名類:帶參方法
        frenchGreeting.greetSomeone("帶參");
    }

    public static void main(String... args) {
        HelloWorldAnonymousClasses myApp = new HelloWorldAnonymousClasses();
        myApp.sayHello();
    }
           

【輸出】

局部類:無參
局部類:帶參
匿名類:無參
匿名類:帶參
           

【分析】

  代碼裡局部類和匿名類實作的功能是一樣的,内部的方法實作的代碼是也一樣的,差別隻在實作

HelloWorld

接口的地方

局部類的格式是:

  1. 建立局部類并且實作接口:

    class EnglishGreeting implements HelloWorld {...}

  2. 建立局部類的執行個體化對象并用接口類型接收:

    HelloWorld englishGreeting = new EnglishGreeting();

  3. 調用執行個體化對象的方法

匿名類的格式是:

  1. 建立匿名類實作接口同時對其進行執行個體化:

    HelloWorld frenchGreeting = new HelloWorld() {...}

  2. 調用執行個體化對象的方法

【差別】

  1. 局部類

    EnglishGreeting

    實作

    HelloWorld

    接口,有自己的類名:

    EnglishGreeting

    ,定義完成後需要再對其執行個體化對象:

    englishGreeting

    才能可以使用方法
  2. 匿名類在定義時就已經執行個體化成對象:

    frenchGreeting

    ,定義完了就可以直接使用方法
  3. 匿名類是一個表達式,是以在定義的最後用分号結束

3. 匿名内部類的文法

3.1 匿名類實作接口

其實上面的示例中的匿名類就是實作接口的方式,這個示例将實作更複雜的功能

public class InterfaceTest {
    public static void main(String[] args) {
        TomInterface tif = new TomInterface() {
            String name = "湯姆";
            @Override
            public void getName() {
                System.out.println(name);
            }

            TomInterface setName(String name){
                this.name = name;
                return this;
            }
        }.setName("傑瑞");
        tif.getName();
    }
}

interface TomInterface{
    void getName();
}
           

【結果】

傑瑞
           

【分析】

  1. main

    方法建立匿名類實作

    TomInterface

    接口并執行個體化:

    new TomInterface{...}

  2. 調用匿名類對象的

    setName

    方法,将

    傑瑞

    指派給匿名類的成員變量

    name

    ,并傳回目前執行個體

    this

    給接口變量

    tif

  3. main

    方法調用匿名類對象的方法

    tif.getName()

    ,而此時的匿名類的成員變量

    name

    的值已經被替換成

    傑瑞

    ,是以最後輸出

    傑瑞

    而不是

    湯姆

3.2 匿名類繼承父類 (匿名子類)

public class ExtendTest {

    public static void main(String[] args) {
        String name = "李四";
        // 建立父類對象,列印原始name值
        PartherClass partherClass = new PartherClass();
        System.out.println("父類的getName方法=" + partherClass.getName());
        // 使用匿名類繼承父類,并列印name值
        PartherClass pc = new PartherClass(name){
            @Override
            public String getName(){
                return "匿名類 - "+super.getName();
            }
        };
        System.out.println(pc.getName());
    }
}

class PartherClass{
    private String name = "張三";
    public PartherClass(){}
    public PartherClass(String name){
        this.name = name;
    }
    public String getName(){
        return this.name;
    }
}
           
父類的getName方法=張三
匿名類 - 李四
           
  1. 建立父類對象并調用

    getName

    方法,這個不用細說
  2. 建立匿名類繼承父類并執行個體化對象:

    pc

    ,本次匿名類調用的是父類的帶參構造,将參數指派給了父類的

    name

  3. 調用匿名類重寫的

    getName

    方法,得到新的

    name

3.3 差別

Demo demo = new Demo(xxx){...}
           
  1. 操作符:new
  2. 一個要實作的接口或要繼承的類,示例3.1 是實作接口,示例3.2 是繼承類
  3. 一對括号,如果是匿名子類,那麼父類有構造參數就填,不帶參就空着;如果匿名類是實作接口,那麼括号裡需要空着
  4. {...}

    ,括号裡括着的是匿名類的聲明主體
  5. 末尾的

    ;

    号,因為匿名類的聲明是一個表達式,是語句的一部分,是以需要分号結尾
  6. 表面上看匿名類沒有類名,沒有構造參數。但其實在編譯的時候,編譯器會給匿名類配置設定類名和構造器,隻是我們無法操作也不能複用。如需驗證,可以看編譯後的class檔案,多出一個命名格式:

    匿名類定義類$?.class

    的檔案。例如示例3.2,匿名類的class檔案就是:

    ExtendTest$1.class