Comment les classes anonymes (internes) sont-elles utilisées en Java?

Quelle est l’utilisation de classes anonymes en Java? Peut-on dire que l’utilisation de la classe anonyme est l’un des avantages de Java?

Par une «classe anonyme», je suppose que vous entendez une classe interne anonyme .

Une classe interne anonyme peut s’avérer utile lors de la création d’une instance d’object avec certains “extras” tels que les méthodes de surcharge, sans avoir à sous-classer une classe.

J’ai tendance à l’utiliser comme raccourci pour attacher un écouteur d’événement:

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

Utiliser cette méthode rend le codage un peu plus rapide, car je n’ai pas besoin de créer une classe supplémentaire qui implémente ActionListener – je peux juste instancier une classe interne anonyme sans créer une classe séparée.

Je n’utilise cette technique que pour des tâches “rapides et sales” où le fait de faire en sorte qu’une classe entière se sente inutile. Avoir plusieurs classes internes anonymes qui font exactement la même chose devrait être restructuré en une classe réelle, que ce soit une classe interne ou une classe distincte.

Les classes internes anonymes sont en fait des fermetures, elles peuvent donc être utilisées pour émuler des expressions lambda ou des “delegates”. Par exemple, prenez cette interface:

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

Vous pouvez l’utiliser anonymement pour créer une fonction de premier ordre en Java. Disons que vous avez la méthode suivante qui renvoie le premier nombre supérieur à i dans la liste donnée, ou i si aucun nombre n’est plus grand:

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

Et puis vous avez une autre méthode qui renvoie le premier nombre plus petit que i dans la liste donnée, ou i si aucun nombre est plus petit:

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

Ces méthodes sont presque identiques. En utilisant le type de fonction F de première classe, nous pouvons les réécrire en une méthode comme suit:

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

Vous pouvez utiliser une classe anonyme pour utiliser la méthode firstMatch:

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

Ceci est un exemple vraiment artificiel, mais il est facile de voir que le fait de pouvoir passer des fonctions comme si elles étaient des valeurs est une fonctionnalité très utile. Voir "Est-ce que votre langage de programmation peut le faire" par Joel lui-même.

Une belle bibliothèque pour programmer Java dans ce style: Java fonctionnel.

Je les utilise parfois comme un hack de syntaxe pour l’instanciation de la carte:

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

contre

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

Cela permet d’économiser de la redondance lors de nombreuses déclarations. Cependant, j’ai également rencontré des problèmes lorsque la classe externe doit être sérialisée via Remoting.

La classe interne anonyme est utilisée dans le scénario suivant:

1.) Pour la substitution (sous-classement), lorsque la définition de classe n’est pas utilisable, sauf la casse courante:

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

2.) Pour implémenter une interface, Quand l’implémentation de l’interface est requirejse uniquement pour le cas courant:

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

3.) Argument Defined Classe interne anonyme:

  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"); } }); } } 

Ils sont couramment utilisés comme une forme verbeuse de rappel.

Je suppose que vous pourriez dire qu’ils sont un avantage par rapport à ne pas en avoir, et avoir à créer une classe nommée à chaque fois, mais des concepts similaires sont beaucoup mieux implémentés dans d’autres langues (comme les fermetures ou les blocs)

Voici un exemple de swing

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

Bien qu’il soit encore verbeux, il vaut beaucoup mieux que de vous obliger à définir une classe nommée pour chaque écouteur comme celui-ci (bien que, selon la situation et la réutilisation, ce soit toujours la meilleure approche)

Vous l’utilisez dans des situations où vous devez créer une classe à une fin spécifique dans une autre fonction, par exemple, en tant qu’écouteur, en tant qu’exécutable (pour générer un thread), etc.

L’idée est que vous les appelez depuis le code d’une fonction afin de ne jamais les consulter ailleurs, vous n’avez donc pas besoin de les nommer. Le compilateur les énumère simplement.

Ils sont essentiellement du sucre syntaxique et devraient généralement être déplacés ailleurs lorsqu’ils grossissent.

Je ne suis pas sûr que ce soit l’un des avantages de Java, même si vous les utilisez (et que nous les utilisons tous malheureusement, malheureusement), vous pourriez en faire valoir un.

GuideLines pour la classe anonyme.

  1. La classe anonyme est déclarée et initialisée simultanément.

  2. La classe anonyme doit étendre ou implémenter une et une seule classe ou interface resp.

  3. Comme la classe anonymouse n’a pas de nom, elle ne peut être utilisée qu’une seule fois.

par exemple:

 button.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent arg0) { // TODO Auto-generated method stub } }); 
 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(); 

C’est aussi un exemple de type interne anonyme utilisant un thread

Oui, les classes internes anonymes sont certainement l’un des avantages de Java.

Avec une classe interne anonyme, vous avez access aux variables finales et aux variables membres de la classe environnante, ce qui est pratique pour les écouteurs, etc.

Mais un avantage majeur est que le code de la classe interne, qui est (au moins devrait être) étroitement couplé à la classe / méthode / bloc environnante, a un contexte spécifique (la classe, la méthode et le bloc environnants).

J’utilise des objects anonymes pour appeler de nouveaux threads.

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

La classe interne anonyme peut être bénéfique tout en offrant différentes implémentations pour différents objects. Mais devrait être utilisé avec parcimonie car cela crée un problème pour la lisibilité du programme.

Une classe interne est associée à une instance de la classe externe et il existe deux types spéciaux: classe locale et classe anonyme . Une classe anonyme nous permet de déclarer et d’instancier une classe en même temps, ce qui rend le code concis. Nous les utilisons lorsque nous avons besoin d’une classe locale une seule fois car ils n’ont pas de nom.

Prenons l’exemple de doc où nous avons une classe Person :

 public class Person { public enum Sex { MALE, FEMALE } Ssortingng name; LocalDate birthday; Sex gender; Ssortingng emailAddress; public int getAge() { // ... } public void printPerson() { // ... } } 

et nous avons une méthode pour imprimer les membres qui correspondent aux critères de recherche comme suit:

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

CheckPerson est une interface comme:

 interface CheckPerson { boolean test(Person p); } 

Maintenant, nous pouvons utiliser une classe anonyme qui implémente cette interface pour spécifier des critères de recherche tels que:

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

Ici, l'interface est très simple et la syntaxe de la classe anonyme semble lourde et peu claire.

Java 8 a introduit un terme d' interface fonctionnelle qui est une interface avec une seule méthode abstraite. Nous pouvons donc dire que CheckPerson est une interface fonctionnelle. Nous pouvons utiliser l' expression Lambda qui nous permet de passer la fonction comme argument de méthode comme:

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

Nous pouvons utiliser une interface fonctionnelle standard Predicate à la place de l'interface CheckPerson , ce qui réduira davantage la quantité de code requirejse.

L’une des principales utilisations des classes anonymes dans la finalisation des classes, appelée gardien du finaliseur . En Java, l’utilisation des méthodes de finalisation doit être évitée jusqu’à ce que vous en ayez vraiment besoin. Vous devez vous rappeler que lorsque vous remplacez la méthode super.finalize() pour des sous-classes, vous devez toujours invoquer super.finalize() , car la méthode super.finalize() de la super classe ne sera pas appelée automatiquement et vous pouvez rencontrer des problèmes de mémoire.

Donc, compte tenu du fait mentionné ci-dessus, vous pouvez simplement utiliser les classes anonymes comme:

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

En utilisant cette technique, vous vous êtes, vous et les autres développeurs, super.finalize() appeler super.finalize() sur chaque sous-classe du HeavyClass qui nécessite une méthode de finalisation.

Vous pouvez utiliser un cours anonyme de cette façon

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

Il semblerait que personne ne soit mentionné ici, mais vous pouvez également utiliser une classe anonyme pour contenir un argument de type générique (qui est normalement perdu à cause de l’effacement de type) :

 public abstract class TypeHolder { 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; } } 

Si vous instanciez cette classe de manière anonyme

 TypeHolder, Map> holder = new TypeHolder, Map>() {}; 

alors une telle instance de holder contiendra une définition non effacée du type passé.

Usage

Ceci est très pratique pour créer des validateurs / désérialisateurs. Vous pouvez également instancier des types génériques avec reflection (donc si vous avez toujours voulu faire un new T() dans un type paramétré, vous êtes les bienvenus!) .

Inconvénients / Limitations

  1. Vous devez passer explicitement le paramètre générique. Ne pas le faire entraînera une perte de paramètre de type
  2. Chaque instanciation vous coûtera une classe supplémentaire à générer par le compilateur, ce qui conduit à une pollution de classpath / des ballonnements de jar

La meilleure façon d’optimiser le code. Nous pouvons également utiliser une méthode de substitution d’une classe ou d’une interface.

 import java.util.Scanner; abstract class AnonymousInner { abstract void sum(); } class AnonymousInnerMain { public static void main(Ssortingng []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(); } } 

Une classe interne anonyme est utilisée pour créer un object qui ne sera plus jamais référencé. Il n’a pas de nom et est déclaré et créé dans la même déclaration. Ceci est utilisé lorsque vous utilisez normalement la variable d’un object. Vous remplacez la variable par le new mot-clé, un appel à un constructeur et la définition de classe dans { et } .

Lors de l’écriture d’un programme fileté en Java, cela ressemblerait généralement à ceci:

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

Le ThreadClass utilisé ici serait défini par l’utilisateur. Cette classe implémentera l’interface Runnable requirejse pour créer des threads. Dans ThreadClass la méthode run() (seule méthode dans Runnable ) doit également être implémentée. Il est clair que se débarrasser de ThreadClass serait plus efficace et c’est précisément pour cette raison que les classes ThreadClass anonymes existent.

Regardez le code suivant

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

Ce code remplace la référence faite à la task dans l’exemple le plus haut. Plutôt que d’avoir une classe séparée, la classe interne anonyme à l’intérieur du constructeur Thread() renvoie un object non nommé qui implémente l’interface Runnable et remplace la méthode run() . La méthode run() inclurait les instructions qui font le travail requirejs par le thread.

En réponse à la question de savoir si Anonymous Inner Classes est l’un des avantages de Java, je dois dire que je ne suis pas tout à fait sûr car je ne connais pas beaucoup de langages de programmation pour le moment. Mais ce que je peux dire, c’est que c’est une méthode de codage plus rapide et plus facile.

Références: Sams vous enseigner Java en 21 jours Septième édition

Un autre avantage:
Comme vous le savez, Java ne prend pas en charge l’inheritance multiple, donc si vous utilisez une classe de type “Thread” en tant que classe anonyme, la classe a encore un espace pour l’extension.