Qual è l'uso di classi anonime in Java? Possiamo dire che l'uso della classe anonima è uno dei vantaggi di Java?
Qual è l'uso di classi anonime in Java? Possiamo dire che l'uso della classe anonima è uno dei vantaggi di Java?
Risposte:
Per "classe anonima", suppongo che intendi classe interna anonima .
Una classe interna anonima può rivelarsi utile quando si crea un'istanza di un oggetto con determinati "extra" come metodi di sostituzione, senza dover effettivamente sottoclassare una classe.
Tendo a usarlo come scorciatoia per allegare un listener di eventi:
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// do something
}
});
L'uso di questo metodo rende la codifica un po 'più veloce, poiché non ho bisogno di creare una classe aggiuntiva che implementa ActionListener
- posso solo creare un'istanza di una classe interna anonima senza effettivamente creare una classe separata.
Uso questa tecnica solo per compiti "veloci e sporchi" in cui non è necessaria la creazione di un'intera classe. Avere più classi interne anonime che fanno esattamente la stessa cosa dovrebbe essere refactored in una classe reale, sia essa una classe interna o una classe separata.
overloading methods
e no overriding methods
?
Le classi interne anonime sono effettivamente chiusure, quindi possono essere utilizzate per emulare espressioni lambda o "delegati". Ad esempio, prendi questa interfaccia:
public interface F<A, B> {
B f(A a);
}
Puoi usarlo in forma anonima per creare una funzione di prima classe in Java. Supponiamo che tu abbia il seguente metodo che restituisce il primo numero più grande di i nell'elenco dato, oppure i se nessun numero è più grande:
public static int larger(final List<Integer> ns, final int i) {
for (Integer n : ns)
if (n > i)
return n;
return i;
}
E poi hai un altro metodo che restituisce il primo numero più piccolo di me nell'elenco dato, o i se nessun numero è più piccolo:
public static int smaller(final List<Integer> ns, final int i) {
for (Integer n : ns)
if (n < i)
return n;
return i;
}
Questi metodi sono quasi identici. Usando il tipo di funzione di prima classe F, possiamo riscriverli in un metodo come segue:
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;
}
È possibile utilizzare una classe anonima per utilizzare il metodo firstMatch:
F<Integer, Boolean> greaterThanTen = new F<Integer, Boolean> {
Boolean f(final Integer n) {
return n > 10;
}
};
int moreThanMyFingersCanCount = firstMatch(xs, greaterThanTen, x);
Questo è un esempio davvero inventato, ma è facile vedere che essere in grado di trasmettere funzioni come se fossero valori è una caratteristica piuttosto utile. Vedi "Può il tuo linguaggio di programmazione farlo" di Joel stesso.
Una libreria piacevole per programmare Java in questo stile: Java funzionale.
La classe interna anonima viene utilizzata nel seguente scenario:
1.) Per l'override (sottoclasse), quando la definizione della classe non è utilizzabile tranne il caso corrente:
class A{
public void methodA() {
System.out.println("methodA");
}
}
class B{
A a = new A() {
public void methodA() {
System.out.println("anonymous methodA");
}
};
}
2.) Per l'implementazione di un'interfaccia, quando l'implementazione dell'interfaccia è richiesta solo per il caso corrente:
interface interfaceA{
public void methodA();
}
class B{
interfaceA a = new interfaceA() {
public void methodA() {
System.out.println("anonymous methodA implementer");
}
};
}
3.) Argomento definito classe interna anonima:
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");
}
});
}
}
Li uso a volte come hack di sintassi per l'istanza di Map:
Map map = new HashMap() {{
put("key", "value");
}};
vs
Map map = new HashMap();
map.put("key", "value");
Risparmia un po 'di ridondanza quando si fanno molte dichiarazioni put. Tuttavia, ho anche riscontrato problemi nel fare questo quando la classe esterna deve essere serializzata tramite telecomando.
Sono comunemente usati come una forma dettagliata di callback.
Suppongo che potresti dire che sono un vantaggio rispetto al non averli e alla necessità di creare una classe denominata ogni volta, ma concetti simili sono implementati molto meglio in altre lingue (come chiusure o blocchi)
Ecco un esempio swing
myButton.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
// do stuff here...
}
});
Sebbene sia ancora molto prolisso, è molto meglio che costringerti a definire una classe nominata per ogni ascoltatore a eliminazione come questo (anche se a seconda della situazione e del riutilizzo, potrebbe essere comunque l'approccio migliore)
myButton.addActionListener(e -> { /* do stuff here */})
o myButton.addActionListener(stuff)
sarebbe più difficile.
Lo usi in situazioni in cui devi creare una classe per uno scopo specifico all'interno di un'altra funzione, ad es. Come ascoltatore, come eseguibile (per generare un thread), ecc.
L'idea è che li chiami dall'interno del codice di una funzione in modo da non farvi mai riferimento ad altrove, quindi non è necessario nominarli. Il compilatore li elenca appena.
Sono essenzialmente zucchero sintattico e dovrebbero generalmente essere spostati altrove man mano che crescono.
Non sono sicuro che sia uno dei vantaggi di Java, anche se se li usi (e sfortunatamente li usiamo tutti frequentemente), potresti argomentare che sono uno di questi.
Linee guida per la classe anonima.
La classe anonima viene dichiarata e inizializzata contemporaneamente.
La classe anonima deve essere estesa o implementata a una sola classe o interfaccia resp.
Poiché la classe anonymouse non ha nome, può essere utilizzata una sola volta.
per esempio:
button.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent arg0) {
// TODO Auto-generated method stub
}
});
ref.getClass().newInstance()
.
Sì, le classi interne anonime sono sicuramente uno dei vantaggi di Java.
Con una classe interna anonima hai accesso alle variabili finali e dei membri della classe circostante, e ciò risulta utile negli ascoltatori ecc.
Ma un grande vantaggio è che il codice della classe interna, che è (almeno dovrebbe essere) strettamente accoppiato alla classe / metodo / blocco circostante, ha un contesto specifico (classe, metodo e blocco circostanti).
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();
Questo è anche uno degli esempi di tipo interno anonimo che utilizza thread
io uso oggetti anonimi per chiamare nuovi thread ..
new Thread(new Runnable() {
public void run() {
// you code
}
}).start();
Una classe interna è associata a un'istanza della classe esterna e ci sono due tipi speciali: classe locale e classe anonima . Una classe anonima ci consente di dichiarare e creare un'istanza di una classe contemporaneamente, rendendo quindi il codice conciso. Li usiamo quando abbiamo bisogno di una classe locale solo una volta perché non hanno un nome.
Considera l'esempio di doc in cui abbiamo una Person
classe:
public class Person {
public enum Sex {
MALE, FEMALE
}
String name;
LocalDate birthday;
Sex gender;
String emailAddress;
public int getAge() {
// ...
}
public void printPerson() {
// ...
}
}
e abbiamo un metodo per stampare membri che corrispondono ai criteri di ricerca come:
public static void printPersons(
List<Person> roster, CheckPerson tester) {
for (Person p : roster) {
if (tester.test(p)) {
p.printPerson();
}
}
}
dove si CheckPerson
trova un'interfaccia come:
interface CheckPerson {
boolean test(Person p);
}
Ora possiamo fare uso di una classe anonima che implementa questa interfaccia per specificare i criteri di ricerca come:
printPersons(
roster,
new CheckPerson() {
public boolean test(Person p) {
return p.getGender() == Person.Sex.MALE
&& p.getAge() >= 18
&& p.getAge() <= 25;
}
}
);
Qui l'interfaccia è molto semplice e la sintassi della classe anonima sembra ingombrante e poco chiara.
Java 8 ha introdotto un termine Interface funzionale che è un'interfaccia con un solo metodo astratto, quindi possiamo dire che CheckPerson
è un'interfaccia funzionale. Possiamo usare Lambda Expression che ci consente di passare la funzione come argomento del metodo come:
printPersons(
roster,
(Person p) -> p.getGender() == Person.Sex.MALE
&& p.getAge() >= 18
&& p.getAge() <= 25
);
Possiamo usare un'interfaccia funzionale standard Predicate
al posto dell'interfaccia CheckPerson
, che ridurrà ulteriormente la quantità di codice richiesto.
La classe interna anonima può essere utile mentre fornisce implementazioni diverse per oggetti diversi. Ma dovrebbe essere usato con parsimonia in quanto crea problemi per la leggibilità del programma.
Uno dei principali utilizzi delle classi anonime nella finalizzazione delle classi che chiamava finalizer guardian . Nel mondo Java l'uso dei metodi finalize dovrebbe essere evitato fino a quando non ne avrete davvero bisogno. Devi ricordare che, quando esegui l'override del metodo finalize per le sottoclassi, devi sempre invocaresuper.finalize()
anche, poiché il metodo finalize della superclasse non invocherà automaticamente e potresti avere problemi con le perdite di memoria.
quindi considerando il fatto sopra menzionato, puoi semplicemente usare le classi anonime come:
public class HeavyClass{
private final Object finalizerGuardian = new Object() {
@Override
protected void finalize() throws Throwable{
//Finalize outer HeavyClass object
}
};
}
Usando questa tecnica hai sollevato te stesso e gli altri sviluppatori affinché invocassero super.finalize()
ciascuna sottoclasse del HeavyClass
metodo che necessita di finalizzazione.
Sembra che nessuno abbia menzionato qui, ma puoi anche usare una classe anonima per contenere argomenti di tipo generico (che normalmente perdono a causa della cancellazione del tipo) :
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;
}
}
Se istanzerai questa classe in modo anonimo
TypeHolder<List<String>, Map<Ineger, Long>> holder =
new TypeHolder<List<String>, Map<Ineger, Long>>() {};
allora tale holder
istanza conterrà una definizione non cancellata di tipo passato.
Questo è molto utile per la costruzione di validatori / deserializzatori. Inoltre puoi istanziare il tipo generico con la riflessione (quindi se hai mai voluto fare un new T()
tipo parametrizzato, sei il benvenuto!) .
Il modo migliore per ottimizzare il codice. inoltre, possiamo usare per un metodo prioritario di una classe o interfaccia.
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();
}
}
Una classe interna anonima viene utilizzata per creare un oggetto a cui non verrà mai più fatto riferimento. Non ha nome ed è dichiarato e creato nella stessa istruzione. Questo è usato dove normalmente useresti la variabile di un oggetto. Sostituisci la variabile con la new
parola chiave, una chiamata a un costruttore e la definizione della classe all'interno {
e }
.
Quando si scrive un programma threaded in Java, di solito dovrebbe apparire così
ThreadClass task = new ThreadClass();
Thread runner = new Thread(task);
runner.start();
L' ThreadClass
usato qui sarebbe definito dall'utente. Questa classe implementerà l' Runnable
interfaccia richiesta per la creazione di thread. Nel metodo deve essere implementato anche ThreadClass
il run()
metodo (solo metodo in Runnable
). È chiaro che sbarazzarsi diThreadClass
sarebbe più efficiente ed è esattamente per questo che esistono le classi interne anonime.
Guarda il seguente codice
Thread runner = new Thread(new Runnable() {
public void run() {
//Thread does it's work here
}
});
runner.start();
Questo codice sostituisce il riferimento fatto task
nell'esempio più in alto. Anziché avere una classe separata, la Classe interna anonima all'interno del Thread()
costruttore restituisce un oggetto senza nome che implementa l' Runnable
interfaccia e sovrascrive il run()
metodo. Il metodo run()
includerebbe istruzioni all'interno che svolgono il lavoro richiesto dal thread.
Rispondendo alla domanda se le classi interne anonime sono uno dei vantaggi di Java, dovrei dire che non sono del tutto sicuro poiché al momento non ho familiarità con molti linguaggi di programmazione. Ma quello che posso dire è che è sicuramente un metodo di codifica più rapido e semplice.
Riferimenti: Sams insegna a te stesso in Java in 21 giorni della settima edizione