Heim  >  Artikel  >  Java  >  Sprechen Sie über die anonymen inneren Klassen von Java

Sprechen Sie über die anonymen inneren Klassen von Java

高洛峰
高洛峰Original
2016-12-15 12:48:421233Durchsuche

In vielen Fällen müssen wir eine statische Karte oder Liste innerhalb der Klasse initialisieren und dann den konstanten Wert zur Verwendung durch die internen Methoden der Klasse speichern.
Unser üblicher Ansatz ist:
Initialisieren Sie zunächst eine statische Variable von Map.
Dann fügen Sie den konstanten Wert im statischen Block hinzu:

Java-Code

private final static Map<String, String> CONSTANT =   
    new HashMap<String, String>();  
static {  
    CONSTANT.put("1", "one");  
    CONSTANT.put("2", "two");  
}

Tatsächlich können Sie auch so schreiben:

Java-Code

private final static Map<String, String> CONSTANT =   
     new HashMap<String, String>() {  
    {  
        put("1", "one");  
        put("2", "two");  
    }  
};

Wenn Sie mit dieser Methode nicht vertraut sind, schauen Sie sich zuerst einen vertrauten an:

Java-Code

new Thread() {  
    public void run() {  
        System.out.println("Thread running!");  
    };  
}.start();

Eigentlich Was der obige Code bedeutet: Deklarieren Sie eine Unterklasse von Thread und überschreiben Sie die run()-Methode von Thread. Erstellen Sie dann eine Instanz der Unterklasse und rufen Sie deren start()-Methode auf. Da die deklarierte Unterklasse von Thread keinen Namen hat, wird sie als anonyme Klasse bezeichnet. Und weil eine Klasse ohne Namen nur innerhalb einer Klasse oder Methode existieren kann, wird sie auch als anonyme innere Klasse bezeichnet.

Die Syntax anonymer innerer Klassen kann auch so geschrieben werden:

Java-Code

Thread thread = new Thread() {  
    public void run() {  
        System.out.println("Thread running!");  
    };  
};   
thread.start();

Der einzige Unterschied besteht darin, dass nicht direkt eine Unterklasse erstellt wird und seine Methode aufrufen, Deklarieren Sie stattdessen einen Thread, auf den die übergeordnete Klasse der Unterklasse verweist, und rufen Sie dann die Methode der Unterklasse über die Referenz der übergeordneten Klasse auf.
Nach dem Erstellen einer Instanz einer anonymen Klasse wird start() nicht sofort ausgeführt, und die Methoden zum Erstellen einer Instanz und zum Ausführen der Instanz sind getrennt.

Der Unterschied zwischen den beiden entspricht:

Java-Code

//1  
new User().setName("Boyce Zhang");  
  
//2  
User user = new User();  
user.setName("Boyce Zhang");

Ein weiteres Syntaxszenario für anonyme innere Klassen:

Java-Code

new Thread() {  
    public void run() {  
        System.out.println("Thread running!");  
    };  
    {  
        start();  
    }  
};

Tatsächlich besteht diese Schreibweise darin, die Klassenmethode der anonymen Unterklasse im lokalen Codeblock der Klasse aufzurufen.
Anweisungen innerhalb eines lokalen Codeblocks werden implizit vom Klassenlader ausgeführt, unmittelbar nachdem eine Instanz der Klasse erstellt wurde.
Entspricht:

Java-Code

public class MyThread extends Thread {  
    {  
        start();  
    }  
    public void run() {  
        System.out.println("Thread running!");  
    };  
}

Bis auf den geringfügigen Unterschied in der Ausführungszeit zwischen den drei Methoden gibt es also keinen großen Unterschied in der Wirkung.

Auf diese Weise ist die vorherige Methode zum Initialisieren von Map nicht schwer zu verstehen:

Java-Code

private final static Map<String, String> CONSTANT = new HashMap<String, String>() {  
    {  
        put("1", "one");  
        put("2", "two");  
    }  
};

Das Prinzip lautet:
Deklaration und Instanz Erstellen Sie eine Unterklasse von HashMap (die Unterklasse überschreibt keine Methoden der übergeordneten Klasse HashMap) und rufen Sie die put()-Methode der übergeordneten Klasse HashMap im klassenlokalen Codeblock der Unterklasse auf.
Deklarieren Sie abschließend eine Map-Schnittstellenreferenz CONSTANT, die auf eine Instanz der instanziierten HashMap-Unterklasse verweist.
Basierend auf dem vorherigen Beispiel wissen wir, dass der Methodenaufruf put() im lokalen Codeblock der Klasse implizit vom Klassenlader ausgeführt wird, nachdem die anonyme Unterklasse von HashMap instanziiert wurde.

Tatsächlich können Sie für jede Klasse oder Schnittstelle in Java eine anonyme Klasse deklarieren, um sie zu erben oder zu implementieren. Zum Beispiel:

Java-Code

//重写父类方法,局部代码块调用自己重写过的父类方法。  
List<String> list = new ArrayList<String>() {  
    public boolean add(String e) {  
        System.out.println("Cannot add anything!");  
    }  
      
    //代码块的顺序在前后都无所谓,可以出现在类范围的任何位置。  
    {  
        add("Boyce Zhang");  
    }  
};  
  
//局部代码块调用父类方法。  
dao.add(new User(){  
    {  
        setName("Boyce Zhang");  
        setAge(26);  
    }  
});  
  
//重写父类方法  
ThreadLocal<User> threadLocal = new ThreadLocal<User>() {  
    protected String initialValue() {  
        return new User("Boyce Zhang", 26);  
    }  
};

Innerhalb der anonymen Klasse können wir nicht nur die Methoden ihrer übergeordneten Klasse implementieren oder überschreiben.
Und Sie können auch Ihre eigenen Methoden oder die Methoden ihrer übergeordneten Klasse im lokalen Codeblock ihrer Klasse ausführen.
Dies ist keine spezielle Syntax für anonyme innere Klassen, sondern eine Java-Syntax, die für jede Klasse gilt.

Diese Schreibweise wird häufig verwendet, um bestimmte Methoden unmittelbar nach der Instanziierung einer Klasse auszuführen, um die Daten einiger Klasseninstanzen zu initialisieren.
Seine Funktion ist dieselbe, als würde man zuerst eine Klasse instanziieren und dann mithilfe ihrer Referenz die Methode aufrufen, die sofort aufgerufen werden muss, z. B.:

Java-Code

Map<String, String> map = new HashMap<String, String>();  
map.put("1", "one");  
map.put("2", "two");

Der Vorteil der Syntax besteht darin, dass sie einfacher ist. Es ist bequemer, etwas sofort nach der Instanziierung einer Klasse zu tun.
Der Effekt ähnelt ein wenig der Instant-Funktion in Javascript. Aber es gibt einen wesentlichen Unterschied.
Da Javascript nicht das Konzept einer Klasse hat, oder mit anderen Worten, eine Funktion in Javascript eine Klasse und eine Klasse eine Funktion ist, führt die Instant-Funktion nach dem Laden die gesamte Funktion aus. Der lokale Codeblock von Java kann jede beliebige Methode der Klasse ausführen.

Natürlich hat diese Schreibweise auch ihre Nachteile:
Jede Instanz einer inneren Klasse enthält implizit einen Verweis auf die äußere Klasse (mit Ausnahme statischer innerer Klassen). ist eine Verschwendung redundanter Referenzen. Andererseits wird bei der Serialisierung dieser Unterklasseninstanz auch die externe Klasse unbewusst serialisiert. Wenn die externe Klasse die Serialisierungsschnittstelle nicht implementiert, wird ein Fehler gemeldet.


Weitere Artikel über die anonymen inneren Klassen von Java finden Sie auf der chinesischen PHP-Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn