it-swarm.com.de

Wie werden anonyme (innere) Klassen in Java verwendet?

Was ist die Verwendung von anonymen Klassen in Java? Können wir sagen, dass die Verwendung anonymer Klassen einer der Vorteile von Java ist?

284
Warrior

Unter einer anonymen Klasse nehme ich an, dass Sie anonymous inner class meinen.

Eine anonyme innere Klasse kann nützlich sein, wenn eine Instanz eines Objekts mit bestimmten "Extras" erstellt wird, z. B. durch Überschreiben von Methoden, ohne dass eine Klasse tatsächlich untergeordnet werden muss.

Ich neige dazu, es als Abkürzung für das Anhängen eines Ereignis-Listeners zu verwenden:

button.addActionListener(new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
        // do something
    }
});

Mit dieser Methode wird die Codierung etwas schneller, da ich keine zusätzliche Klasse erstellen muss, die ActionListener implementiert. Ich kann nur eine anonyme innere Klasse instanziieren, ohne eine separate Klasse zu erstellen.

Ich verwende diese Technik nur für "schnelle und schmutzige" Aufgaben, bei denen das Erstellen einer ganzen Klasse unnötig erscheint. Mehrere anonyme innere Klassen, die genau dasselbe tun, sollten auf eine tatsächliche Klasse umgestaltet werden, sei es eine innere Klasse oder eine separate Klasse.

348
coobird

Anonyme innere Klassen sind praktisch Schließungen, sodass sie zum Nachahmen von Lambda-Ausdrücken oder "Delegierten" verwendet werden können. Nehmen Sie zum Beispiel diese Schnittstelle:

public interface F<A, B> {
   B f(A a);
}

Sie können dies anonym verwenden, um eine erstklassige Funktion in Java zu erstellen. Angenommen, Sie haben die folgende Methode, die die erste Zahl größer als i in der angegebenen Liste zurückgibt, oder i, wenn keine Zahl größer ist:

public static int larger(final List<Integer> ns, final int i) {
  for (Integer n : ns)
     if (n > i)
        return n;
  return i;
}

Und dann haben Sie eine andere Methode, die die erste Zahl kleiner als i in der angegebenen Liste zurückgibt, oder i, wenn keine Zahl kleiner ist:

public static int smaller(final List<Integer> ns, final int i) {
   for (Integer n : ns)
      if (n < i)
         return n;
   return i;
}

Diese Methoden sind fast identisch. Mit dem erstklassigen Funktionstyp F können wir diese wie folgt in eine Methode umschreiben:

public static <T> T firstMatch(final List<T> ts, final F<T, Boolean> f, T z) {
   for (T t : ts)
      if (f.f(t))
         return t;
   return z;
}

Sie können eine anonyme Klasse verwenden, um die firstMatch-Methode zu verwenden:

F<Integer, Boolean> greaterThanTen = new F<Integer, Boolean> {
   Boolean f(final Integer n) {
      return n > 10;
   }
};
int moreThanMyFingersCanCount = firstMatch(xs, greaterThanTen, x);

Dies ist ein wirklich durchdachtes Beispiel, aber es ist leicht zu sehen, dass es eine sehr nützliche Funktion ist, Funktionen wie Werte weitergeben zu können. Siehe "Kann Ihre Programmiersprache dies tun" von Joel selbst.

Eine schöne Bibliothek zur Programmierung von Java in diesem Stil: Funktionales Java.

70
Apocalisp

Anonyme innere Klasse wird in folgendem Szenario verwendet:

1.) Zum Überschreiben (Unterklassifizierung), wenn Klassendefinition außer im aktuellen Fall nicht verwendbar ist:

class A{
   public void methodA() {
      System.out.println("methodA");
    }
}
class B{
    A a = new A() {
     public void methodA() {
        System.out.println("anonymous methodA");
     }
   };
}

2.) Um eine Schnittstelle zu implementieren, Wenn die Implementierung einer Schnittstelle nur für den aktuellen Fall erforderlich ist:

interface interfaceA{
   public void methodA();
}
class B{
   interfaceA a = new interfaceA() {
     public void methodA() {
        System.out.println("anonymous methodA implementer");
     }
   };
}

3.) Argument definierte anonyme innere Klasse:

 interface Foo {
   void methodFoo();
 }
 class B{
  void do(Foo f) { }
}

class A{
   void methodA() {
     B b = new B();
     b.do(new Foo() {
       public void methodFoo() {
         System.out.println("methodFoo");
       } 
     });
   } 
 } 
47
Sandeep Kumar

Ich benutze sie manchmal als Syntax-Hack für die Map-Instantiierung:

Map map = new HashMap() {{
   put("key", "value");
}};

vs

Map map = new HashMap();
map.put("key", "value");

Es spart etwas Redundanz, wenn viele Put-Anweisungen ausgeführt werden. Ich habe jedoch auch Probleme damit, wenn die äußere Klasse per Remoting serialisiert werden muss. 

44
Chase Seibert

Sie werden häufig als ausführliche Form von Rückruf verwendet.

Ich denke, Sie könnten sagen, dass sie einen Vorteil haben, wenn sie nicht vorhanden sind und jedes Mal eine benannte Klasse erstellt werden müssen. Ähnliche Konzepte werden jedoch in anderen Sprachen (als Schließungen oder Blöcke) viel besser implementiert.

Hier ist ein Schaukelbeispiel

myButton.addActionListener(new ActionListener(){
    public void actionPerformed(ActionEvent e) {
        // do stuff here...
    }
});

Obwohl es immer noch unordentlich ausführlich ist, ist es viel besser, als dass Sie gezwungen werden, eine benannte Klasse für jeden Wegwerf-Listener wie diesen zu definieren (obwohl dies je nach Situation und Wiederverwendung der bessere Ansatz sein kann)

17
madlep

Sie verwenden es in Situationen, in denen Sie eine Klasse für einen bestimmten Zweck in einer anderen Funktion erstellen müssen, z. B. als Listener, als Runable (um einen Thread zu erzeugen) usw.

Die Idee ist, dass Sie sie aus dem Code einer Funktion heraus aufrufen, sodass Sie sie niemals an anderer Stelle referenzieren, so dass Sie sie nicht benennen müssen. Der Compiler zählt sie nur auf.

Sie sind im Wesentlichen syntaktischer Zucker und sollten im Allgemeinen an anderer Stelle verschoben werden, wenn sie größer werden.

Ich bin mir nicht sicher, ob dies einer der Vorteile von Java ist. Wenn Sie sie jedoch verwenden (und wir alle verwenden sie leider häufig), könnten Sie argumentieren, dass sie eins sind.

7
Uri

Führungslinien für anonyme Klassen.

  1. Die anonyme Klasse wird gleichzeitig deklariert und initialisiert.

  2. Die anonyme Klasse muss sich auf eine und nur eine Klasse bzw. Schnittstelle erweitern bzw. implementieren.

  3. Da die anonymouse-Klasse keinen Namen hat, kann sie nur einmal verwendet werden.

z.B: 

button.addActionListener(new ActionListener(){

            public void actionPerformed(ActionEvent arg0) {
        // TODO Auto-generated method stub

    }
});
6
new Thread() {
        public void run() {
            try {
                Thread.sleep(300);
            } catch (InterruptedException e) {
                System.out.println("Exception message: " + e.getMessage());
                System.out.println("Exception cause: " + e.getCause());
            }
        }
    }.start();

Dies ist auch eines der Beispiele für anonyme Innentypen, die Thread verwenden

5
raja

Ja, anonyme innere Klassen sind definitiv einer der Vorteile von Java.

Mit einer anonymen inneren Klasse haben Sie Zugriff auf End- und Membervariablen der umgebenden Klasse. Dies ist für Hörer usw. von Vorteil.

Ein großer Vorteil besteht jedoch darin, dass der innere Klassencode, der eng mit der umgebenden Klasse/Methode/Block verbunden ist (zumindest sollte), einen bestimmten Kontext hat (die umgebende Klasse, Methode und Block).

4

ich benutze anonyme Objekte, um neue Threads aufzurufen.

new Thread(new Runnable() {
    public void run() {
        // you code
    }
}).start();
4
user2837260

Eine innere Klasse ist einer Instanz der äußeren Klasse zugeordnet, und es gibt zwei spezielle Arten: Lokale Klasse und Anonyme Klasse . Eine anonyme Klasse ermöglicht es uns, eine Klasse gleichzeitig zu deklarieren und zu instanziieren, wodurch der Code kurz gefasst wird. Wir verwenden sie, wenn wir nur einmal eine lokale Klasse benötigen, da sie keinen Namen haben.

Betrachten Sie das Beispiel aus doc wo wir eine Person-Klasse haben:

public class Person {

    public enum Sex {
        MALE, FEMALE
    }

    String name;
    LocalDate birthday;
    Sex gender;
    String emailAddress;

    public int getAge() {
        // ...
    }

    public void printPerson() {
        // ...
    }
}

und wir haben eine Methode, um Mitglieder, die den Suchkriterien entsprechen, zu drucken:

public static void printPersons(
    List<Person> roster, CheckPerson tester) {
    for (Person p : roster) {
        if (tester.test(p)) {
            p.printPerson();
        }
    }
}

dabei ist CheckPerson eine Schnittstelle wie:

interface CheckPerson {
    boolean test(Person p);
}

Jetzt können wir die anonyme Klasse verwenden, die diese Schnittstelle implementiert, um Suchkriterien wie folgt anzugeben:

printPersons(
    roster,
    new CheckPerson() {
        public boolean test(Person p) {
            return p.getGender() == Person.Sex.MALE
                && p.getAge() >= 18
                && p.getAge() <= 25;
        }
    }
);

Hier ist die Schnittstelle sehr einfach und die Syntax der anonymen Klasse erscheint unhandlich und unklar.

Java 8 hat einen Begriff Functional Interface eingeführt, bei dem es sich um eine Schnittstelle mit nur einer abstrakten Methode handelt. Daher können wir sagen, dass CheckPerson eine funktionale Schnittstelle ist. Wir können Lambda Expression verwenden, um die Funktion als Methodenargument zu übergeben:

printPersons(
                roster,
                (Person p) -> p.getGender() == Person.Sex.MALE
                        && p.getAge() >= 18
                        && p.getAge() <= 25
        );

Anstelle der Schnittstelle Predicate können wir eine Standardfunktionsschnittstelle CheckPerson verwenden, die die erforderliche Code-Menge weiter reduziert.

2
i_am_zero

Eine anonyme innere Klasse kann vorteilhaft sein, während verschiedene Implementierungen für verschiedene Objekte angegeben werden. Es sollte jedoch sehr sparsam eingesetzt werden, da dies zu Problemen bei der Programmlesbarkeit führt.

2
user1923551

Eine der Hauptanwendungen anonymer Klassen in der Klassen-Finalisierung, die Finalizer Guardian genannt. In Java sollte die Verwendung der Finalize-Methoden so lange vermieden werden, bis Sie sie wirklich brauchen. Wenn Sie die finalize-Methode für Unterklassen überschreiben, sollten Sie immer auch super.finalize() aufrufen, da die finalize-Methode der Superklasse nicht automatisch aufgerufen wird und Sie Probleme mit Speicherverlusten haben können.

in Anbetracht der oben genannten Tatsache können Sie einfach die anonymen Klassen verwenden:

public class HeavyClass{
    private final Object finalizerGuardian = new Object() {
        @Override
        protected void finalize() throws Throwable{
            //Finalize outer HeavyClass object
        }
    };
}

Mit dieser Technik haben Sie sich und Ihre anderen Entwickler entlastet, um super.finalize() für jede Unterklasse der HeavyClass aufzurufen, die die Methode finalize benötigt.

1
Hazhir

Anscheinend wurde hier nichts erwähnt, aber Sie können auch eine anonyme Klasse verwenden, um das generische Typargument zu speichern (das normalerweise durch das Löschen von Typen verloren ging) :

public abstract class TypeHolder<T> {
    private final Type type;

    public TypeReference() {
        // you may do do additional sanity checks here
        final Type superClass = getClass().getGenericSuperclass();
        this.type = ((ParameterizedType) superClass).getActualTypeArguments()[0];
    }

    public final Type getType() {
        return this.type;
    }
}

Wenn Sie diese Klasse auf anonyme Weise instanziieren 

TypeHolder<List<String>, Map<Ineger, Long>> holder = 
    new TypeHolder<List<String>, Map<Ineger, Long>>() {};

dann enthält diese holder-Instanz eine nicht gelöschte Definition des übergebenen Typs. 

Verwendungszweck

Dies ist sehr praktisch für den Bau von Validatoren/Deserialisatoren. Sie können auch einen generischen Typ mit Reflektion instanziieren (wenn Sie also new T() in parametrisiertem Typ machen wollten - Sie sind willkommen!) .

Nachteile/Einschränkungen

  1. Sie sollten generische Parameter explizit übergeben. Andernfalls führt dies zum Verlust von Typparametern
  2. Jede Instantiierung kostet Sie zusätzliche Klasse, die vom Compiler generiert wird, was zu Klassenpfadverschmutzung/Blähungen führt
1
vsminkov

Sie können anonyme Klassen auf diese Weise verwenden

TreeSet treeSetObj = new TreeSet(new Comparator()
{
    public int compare(String i1,String i2)
    {
        return i2.compareTo(i1);
    }
});
1
Saurabh

Eine Anonymous Inner Class wird verwendet, um ein Objekt zu erstellen, auf das nie mehr verwiesen wird. Es hat keinen Namen und wird in derselben Anweisung deklariert und erstellt .. Diese wird verwendet, wenn Sie normalerweise die Objektvariable verwenden würden. Sie ersetzen die Variable durch das Schlüsselwort new, einen Aufruf an einen Konstruktor und die Klassendefinition in { und }.

Wenn Sie ein Threaded-Programm in Java schreiben, sieht es normalerweise so aus

ThreadClass task = new ThreadClass();
Thread runner = new Thread(task);
runner.start();

Die hier verwendete Variable ThreadClass wäre benutzerdefiniert. Diese Klasse implementiert die Runnable-Schnittstelle, die zum Erstellen von Threads erforderlich ist. In der ThreadClass muss auch die run()-Methode (nur Methode in Runnable) implementiert werden. Es ist klar, dass die Beseitigung von ThreadClass effizienter wäre, und genau deshalb gibt es anonyme innere Klassen.

Schauen Sie sich den folgenden Code an 

Thread runner = new Thread(new Runnable() {
    public void run() {
        //Thread does it's work here
    }
});
runner.start();

Dieser Code ersetzt den Verweis auf task im obersten Beispiel. Anstatt über eine separate Klasse zu verfügen, gibt die anonyme innere Klasse im Thread()-Konstruktor ein unbenanntes Objekt zurück, das die Runnable-Schnittstelle implementiert und die run()-Methode überschreibt. Die Methode run() würde Anweisungen enthalten, die die für den Thread erforderliche Arbeit erledigen.

Um die Frage zu beantworten, ob Anonymous Inner Classes einer der Vorteile von Java ist, muss ich sagen, dass ich nicht ganz sicher bin, da ich mit vielen Programmiersprachen im Moment nicht vertraut bin. Was ich aber sagen kann, ist definitiv eine schnellere und einfachere Codierungsmethode.

Referenzen: Sams Teach Yourself Java in 21 Days Seventh Edition

0

Der beste Weg, um den Code zu optimieren. Wir können auch eine überschreibende Methode einer Klasse oder Schnittstelle verwenden. 

import Java.util.Scanner;
abstract class AnonymousInner {
    abstract void sum();
}

class AnonymousInnerMain {
    public static void main(String []k){
        Scanner sn = new Scanner(System.in);
        System.out.println("Enter two vlaues");
            int a= Integer.parseInt(sn.nextLine());
            int b= Integer.parseInt(sn.nextLine()); 
        AnonymousInner ac = new AnonymousInner(){
            void sum(){
                int c= a+b;
                System.out.println("Sum of two number is: "+c);
            }
        };
        ac.sum();
    }

}
0

Ein weiterer Vorteil:
Wie Sie wissen, unterstützt Java keine Mehrfachvererbung. Wenn Sie also die Klasse "Thread" als anonyme Klasse verwenden, hat die Klasse noch einen Platz, den andere Klassen erweitern können.

0
Arun Raaj