Quelle est l'utilisation des classes anonymes en Java? Peut-on dire que l'utilisation de la classe anonyme est l'un des avantages de Java?
Quelle est l'utilisation des classes anonymes en Java? Peut-on dire que l'utilisation de la classe anonyme est l'un des avantages de Java?
Réponses:
Par "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'un objet avec certains "extras" tels que des méthodes de substitution, sans avoir à sous-classer réellement 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
}
});
L'utilisation de 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 simplement instancier une classe interne anonyme sans réellement créer une classe séparée.
J'utilise cette technique uniquement pour les tâches "rapides et sales" où rendre une classe entière semble inutile. Avoir plusieurs classes internes anonymes qui font exactement la même chose devrait être refactorisé en une classe réelle, que ce soit une classe interne ou une classe distincte.
overloading methods
et non overriding methods
?
Les classes internes anonymes sont en réalité des fermetures, elles peuvent donc être utilisées pour émuler des expressions lambda ou des «délégués». Par exemple, prenez cette interface:
public interface F<A, B> {
B f(A a);
}
Vous pouvez l'utiliser de manière anonyme pour créer une fonction de première classe 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<Integer> ns, final int i) {
for (Integer n : ns)
if (n > i)
return n;
return i;
}
Et puis vous avez une autre méthode qui retourne le premier nombre plus petit que i dans la liste donnée, ou i si aucun nombre n'est plus petit:
public static int smaller(final List<Integer> 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 de première classe F, nous pouvons les réécrire en une seule méthode comme suit:
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;
}
Vous pouvez utiliser une classe anonyme pour utiliser la méthode firstMatch:
F<Integer, Boolean> greaterThanTen = new F<Integer, Boolean> {
Boolean f(final Integer n) {
return n > 10;
}
};
int moreThanMyFingersCanCount = firstMatch(xs, greaterThanTen, x);
C'est un exemple vraiment artificiel, mais il est facile de voir qu'être capable de passer des fonctions comme s'il s'agissait de valeurs est une fonctionnalité assez utile. Voir «Votre langage de programmation peut-il le faire» par Joel lui-même.
Une jolie bibliothèque pour programmer Java dans ce style: Java fonctionnel.
La classe interne anonyme est utilisée dans le scénario suivant:
1.) Pour remplacer (sous-classement), lorsque la définition de classe n'est pas utilisable, sauf dans le cas actuel:
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 la mise en œuvre d'une interface, lorsque la mise en œuvre de l'interface n'est requise que pour le cas actuel:
interface interfaceA{
public void methodA();
}
class B{
interfaceA a = new interfaceA() {
public void methodA() {
System.out.println("anonymous methodA implementer");
}
};
}
3.) Classe interne anonyme définie par argument:
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");
}
});
}
}
Je les utilise parfois comme 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");
Il enregistre une certaine redondance lors de l'exécution de nombreuses instructions put. Cependant, j'ai également rencontré des problèmes lors de cette opération lorsque la classe externe doit être sérialisée via l'accès à distance.
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 les avoir et à créer une classe nommée à chaque fois, mais des concepts similaires sont beaucoup mieux implémentés dans d'autres langages (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 toujours très verbeux, c'est beaucoup mieux que de vous forcer à définir une classe nommée pour chaque auditeur à jeter comme ça (bien que selon la situation et la réutilisation, cela peut toujours être la meilleure approche)
myButton.addActionListener(e -> { /* do stuff here */})
ou myButton.addActionListener(stuff)
serait terser.
Vous l'utilisez dans des situations où vous devez créer une classe à des fins spécifiques dans une autre fonction, par exemple, en tant qu'écouteur, en tant que runnable (pour générer un thread), etc.
L'idée est que vous les appeliez depuis l'intérieur du code d'une fonction afin de ne jamais vous y référer 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 à mesure qu'ils grossissent.
Je ne sais pas si c'est l'un des avantages de Java, bien que si vous les utilisez (et nous les utilisons tous fréquemment, malheureusement), alors vous pourriez affirmer qu'ils en sont un.
GuideLines for Anonymous Class.
La classe anonyme est déclarée et initialisée simultanément.
La classe anonyme doit étendre ou implémenter une et une seule classe ou interface resp.
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
}
});
ref.getClass().newInstance()
.
Oui, les classes internes anonymes sont certainement l'un des avantages de Java.
Avec une classe interne anonyme, vous avez accès aux variables finales et membres de la classe environnante, ce qui est pratique pour les auditeurs, etc.
Mais un avantage majeur est que le code de 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).
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 également l'un des exemples de type interne anonyme utilisant un thread
j'utilise des objets anonymes pour appeler de nouveaux Threads ..
new Thread(new Runnable() {
public void run() {
// you code
}
}).start();
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 Person
classe:
public class Person {
public enum Sex {
MALE, FEMALE
}
String name;
LocalDate birthday;
Sex gender;
String 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:
public static void printPersons(
List<Person> roster, CheckPerson tester) {
for (Person p : roster) {
if (tester.test(p)) {
p.printPerson();
}
}
}
où CheckPerson
est une interface comme:
interface CheckPerson {
boolean test(Person p);
}
Nous pouvons maintenant utiliser une classe anonyme qui implémente cette interface pour spécifier des critères de recherche comme:
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 compliquée et peu claire.
Java 8 a introduit un terme interface fonctionnelle qui est une interface avec une seule méthode abstraite, donc nous pouvons dire que CheckPerson
c'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 encore la quantité de code requise.
La classe interne anonyme peut être bénéfique tout en donnant différentes implémentations pour différents objets. Mais doit être utilisé avec parcimonie car cela crée un problème de lisibilité du programme.
L'une des principales utilisations des classes anonymes dans la finalisation des classes qui appelait le gardien du finaliseur . Dans le monde 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 finalize pour les sous-classes, vous devez toujours invoquer super.finalize()
également, car la méthode finalize de super class ne sera pas invoquée automatiquement et vous pouvez avoir des problèmes avec les fuites de mémoire.
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 avez soulagé vous-même et vos autres développeurs d'appeler super.finalize()
chaque sous-classe de la HeavyClass
méthode qui doit être finalisée.
Il semble que personne ne soit mentionné ici, mais vous pouvez également utiliser une classe anonyme pour contenir un argument de type générique (qui a normalement été perdu en raison de l'effacement de type) :
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;
}
}
Si vous instanciez cette classe de manière anonyme
TypeHolder<List<String>, Map<Ineger, Long>> holder =
new TypeHolder<List<String>, Map<Ineger, Long>>() {};
alors cette holder
instance contiendra une définition non effacée du type passé.
C'est très pratique pour construire des validateurs / désérialisateurs. Vous pouvez également instancier un type générique avec réflexion (donc si vous avez toujours voulu le faire new T()
en type paramétré - vous êtes les bienvenus!) .
La meilleure façon d'optimiser le code. aussi, nous pouvons utiliser pour une méthode prioritaire d'une classe ou d'une interface.
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();
}
}
Une classe interne anonyme est utilisée pour créer un objet qui ne sera plus jamais référencé. Il n'a pas de nom et est déclaré et créé dans la même instruction. Ceci est utilisé là où vous utiliseriez normalement la variable d'un objet. Vous remplacez la variable par le new
mot clé, un appel à un constructeur et la définition de classe à l'intérieur de {
et }
.
Lors de l'écriture d'un programme threadé en Java, il ressemblerait généralement à ceci
ThreadClass task = new ThreadClass();
Thread runner = new Thread(task);
runner.start();
L' ThreadClass
utilisé ici serait défini par l'utilisateur. Cette classe implémentera l' Runnable
interface requise pour créer des threads. Dans la ThreadClass
la run()
méthode (seule méthode Runnable
) doit être mis en œuvre aussi bien. Il est clair que se débarrasser de ThreadClass
serait plus efficace et c'est exactement pourquoi il existe des classes internes anonymes.
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 task
dans l'exemple le plus en haut. Plutôt que d'avoir une classe distincte, la classe interne anonyme à l'intérieur du Thread()
constructeur renvoie un objet sans nom qui implémente l' Runnable
interface et remplace la run()
méthode. La méthode run()
comprendrait des instructions à l'intérieur qui effectuent le travail requis par le thread.
Répondant à la question de savoir si les classes internes anonymes est l'un des avantages de Java, je dois dire que je ne suis pas 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 définitivement une méthode de codage plus rapide et plus facile.
Références: Sams Teach Yourself Java in 21 Days Seventh Edition