Uso delle definizioni di class all’interno di un metodo in Java

Esempio:

public class TestClass { public static void main(String[] args) { TestClass t = new TestClass(); } private static void testMethod() { abstract class TestMethod { int a; int b; int c; abstract void implementMe(); } class DummyClass extends TestMethod { void implementMe() {} } DummyClass dummy = new DummyClass(); } } 

Ho scoperto che il codice di cui sopra è perfettamente legale in Java. Ho le seguenti domande.

  1. A che serve avere una definizione di class in un metodo?
  2. Verrà generato un file di class per DummyClass
  3. È difficile per me immaginare questo concetto in un modo orientato agli oggetti. Avere una definizione di class all’interno di un comportamento. Probabilmente qualcuno può dirmi con esempi del mondo reale equivalenti.
  4. Le lezioni astratte all’interno di un metodo mi sembrano un po ‘pazze. Ma nessuna interfaccia consentita. C’è qualche ragione dietro a questo?

Questo è chiamato una class locale.

2 è facile: sì, verrà generato un file di class.

1 e 3 sono una specie della stessa domanda. Dovresti utilizzare una class locale in cui non hai mai bisogno di creare un’istanza o conoscere i dettagli di implementazione, ma in un unico metodo.

Un tipico utilizzo sarebbe la creazione di un’implementazione di alcune interfacce. Ad esempio vedrai spesso qualcosa del genere:

  //within some method taskExecutor.execute( new Runnable() { public void run() { classWithMethodToFire.doSomething( parameter ); } }); 

Se dovessi creare un gruppo di questi e fare qualcosa con loro, potresti cambiarlo

  //within some method class myFirstRunnableClass implements Runnable { public void run() { classWithMethodToFire.doSomething( parameter ); } } class mySecondRunnableClass implements Runnable { public void run() { classWithMethodToFire.doSomethingElse( parameter ); } } taskExecutor.execute(new myFirstRunnableClass()); taskExecutor.execute(new mySecondRunnableClass()); 

Per quanto riguarda le interfacce: non sono sicuro che ci sia un problema tecnico che rende le interfacce definite localmente un problema per il compilatore, ma anche se non lo sono, non aggiungerebbero alcun valore. Se una class locale che implementa un’interfaccia locale fosse utilizzata al di fuori del metodo, l’interfaccia sarebbe priva di significato. E se una class locale dovesse essere utilizzata solo all’interno del metodo, sia l’interfaccia che la class sarebbero implementate all’interno di quel metodo, quindi la definizione dell’interfaccia sarebbe ridondante.

Quelli sono chiamati classi locali . Puoi trovare una spiegazione dettagliata e un esempio qui . L’esempio restituisce un’implementazione specifica che non è necessario conoscere al di fuori del metodo.

  1. La class non può essere vista (cioè istanziata, i suoi metodi sono accessibili senza Reflection) dall’esterno del metodo. Inoltre, può accedere alle variabili locali definite in testMethod (), ma prima della definizione della class.

  2. In realtà ho pensato: “Nessun file verrà scritto”. fino a quando non l’ho appena provato: Oh sì, un tale file è stato creato! Sarà chiamato qualcosa come A $ 1B.class, dove A è la class esterna e B è la class locale.

  3. Soprattutto per le funzioni di callback (gestori di eventi nelle GUI, come onClick () quando si fa clic su un pulsante, ecc.), È piuttosto usuale usare “classi anonime” – innanzitutto perché si possono finire con molte di esse. Ma a volte le classi anonime non sono abbastanza buone, specialmente non è ansible definire un costruttore su di esse. In questi casi, queste classi di metodi locali possono essere una buona alternativa.

Il vero scopo di questo è di permetterci di creare classi in linea in chiamate di funzione per consolare quelli di noi che amano fingere di scrivere in un linguaggio funzionale;)

L’unico caso in cui si desidera avere una funzione di class interna contro class anonima completa (ovvero chiusura Java) è quando si verificano le seguenti condizioni

  1. è necessario fornire un’interfaccia o un’implementazione astratta della class
  2. si desidera utilizzare alcuni parametri finali definiti nella funzione di chiamata
  3. è necessario registrare uno stato di esecuzione della chiamata dell’interfaccia.

Ad esempio qualcuno vuole un Runnable e si desidera registrare quando l’esecuzione è iniziata e terminata.

Con la class anonima non è ansible farlo, con la class interiore puoi farlo.

Ecco un esempio per dimostrare il mio punto

 private static void testMethod ( final Object param1, final Object param2 ) { class RunnableWithStartAndEnd extends Runnable{ Date start; Date end; public void run () { start = new Date( ); try { evalParam1( param1 ); evalParam2( param2 ); ... } finally { end = new Date( ); } } } final RunnableWithStartAndEnd runnable = new RunnableWithStartAndEnd( ); final Thread thread = new Thread( runnable ); thread.start( ); thread.join( ); System.out.println( runnable.start ); System.out.println( runnable.end ); } 

Prima di utilizzare questo modello, valutare se la semplice vecchia class di livello superiore o la class interna o la class interna statica sono alternative migliori.

La ragione principale per definire le classi interne (all’interno di un metodo o di una class) consiste nel trattare l’accessibilità dei membri e delle variabili della class e del metodo che li racchiude. Una class interna può cercare membri di dati privati ​​e operare su di essi. Se all’interno di un metodo si può trattare anche con la variabile locale finale.

Avere classi interne aiuta a fare in modo che questa class non sia accessibile al mondo esterno. Ciò vale in particolare per i casi di programmazione dell’interfaccia utente in GWT o GXT ecc. Dove il codice di generazione JS è scritto in java e il comportamento per ogni pulsante o evento deve essere definito creando classi anonime