web-dev-qa-db-fra.com

Utilisation de définitions de classe dans une méthode de Java

Exemple:

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

J'ai découvert que le code ci-dessus est parfaitement légal en Java. J'ai les questions suivantes.

  1. Quelle est l'utilisation de jamais avoir une définition de classe dans une méthode?
  2. Un fichier de classe sera-t-il généré pour DummyClass
  3. Il m'est difficile d'imaginer ce concept de manière orientée objet. Avoir une définition de classe dans un comportement. Quelqu'un peut-il probablement me donner des exemples équivalents du monde réel?.
  4. Les classes abstraites à l'intérieur d'une méthode me paraissent un peu folles. Mais pas d'interfaces autorisées. Y a-t-il une raison derrière cela?
98
bragboy

Ceci s'appelle une classe locale.

2 est le plus simple: oui, un fichier de classe sera généré.

1 et 3 sont un peu la même question. Vous utiliseriez une classe locale dans laquelle vous n'avez jamais besoin d'instancier ou de connaître les détails de l'implémentation ailleurs que dans une méthode.

Une utilisation typique serait de créer une implémentation jetable de certaines interfaces. Par exemple, vous verrez souvent quelque chose comme ceci:

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

Si vous deviez en créer un ensemble et en faire quelque chose, vous pouvez le changer en

  //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());

En ce qui concerne les interfaces: je ne sais pas s'il existe un problème technique qui fait des interfaces définies localement un problème pour le compilateur, mais même s'il n'y en avait pas, elles ne créeraient aucune valeur. Si une classe locale implémentant une interface locale était utilisée en dehors de la méthode, l'interface n'aurait aucun sens. Et si une classe locale devait uniquement être utilisée dans la méthode, l'interface et la classe seraient implémentées dans cette méthode, de sorte que la définition de l'interface serait redondante.

66
Jacob Mattison

Celles-ci sont appelées des classes locales . Vous pouvez trouver une explication détaillée et un exemple ici . L'exemple retourne une implémentation spécifique que nous n'avons pas besoin de connaître en dehors de la méthode.

15
BalusC
  1. La classe ne peut pas être vue (c'est-à-dire instanciée, ses méthodes accessibles sans réflexion) de l'extérieur de la méthode. En outre, il peut accéder aux variables locales définies dans testMethod (), mais avant la définition de la classe.

  2. J'ai en fait pensé: "Aucun fichier de ce genre ne sera écrit." jusqu'à ce que je viens de l'essayer: Oh oui, un tel fichier est créé! On l'appellera quelque chose comme A $ 1B.class, où A est la classe externe et B est la classe locale.

  3. En particulier pour les fonctions de rappel (gestionnaires d'événements dans les interfaces graphiques, comme onClick () lorsqu'un bouton est cliqué, etc.), il est assez habituel d'utiliser des "classes anonymes", tout d'abord parce que vous pouvez en avoir beaucoup. Mais parfois, les classes anonymes ne suffisent pas - en particulier, vous ne pouvez pas définir un constructeur sur elles. Dans ces cas, ces méthodes locales peuvent être une bonne alternative.

9
Chris Lercher

Le but réel de ceci est de nous permettre de créer des classes en ligne dans les appels de fonctions pour consoler ceux d’entre nous qui aimons prétendre écrire dans un langage fonctionnel;)

7
Steve B.

Le seul cas où vous souhaiteriez avoir une fonction entièrement développée interne et une classe anonyme (a.k.a. Java fermeture)) est lorsque les conditions suivantes sont remplies

  1. vous devez fournir une interface ou une implémentation de classe abstraite
  2. vous voulez utiliser certains paramètres finaux définis dans la fonction d'appel
  3. vous devez enregistrer un certain état d'exécution de l'appel d'interface.

Par exemple. quelqu'un veut un Runnable et vous voulez enregistrer quand l'exécution a commencé et s'est terminée.

Avec une classe anonyme, ce n'est pas possible, avec une classe intérieure, vous pouvez le faire.

Voici un exemple démontre mon point

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

Avant d’utiliser ce modèle, veuillez cependant évaluer si les anciennes classes de classe supérieure, ou internes, ou les classes internes statiques sont tout simplement meilleures.

4

La principale raison de définir des classes internes (au sein d'une méthode ou d'une classe) est de traiter de l'accessibilité des membres et des variables de la classe et de la méthode englobantes. Une classe interne peut rechercher des membres de données privés et les exploiter. Si, dans une méthode, il peut également traiter de la variable locale finale.

Avoir des classes internes aide à s'assurer que cette classe n'est pas accessible au monde extérieur. Ceci est particulièrement vrai pour les cas de programmation d'interface utilisateur dans GWT ou GXT, etc., où le code générateur de JS est écrit en Java et le comportement de chaque bouton ou événement doit être défini en créant des classes anonymes

2
Fazal