2008-10-31 6 views
2

Le code à la fin produit une erreur de compilation:Pourquoi ne puis-je appeler une méthode en dehors d'une classe anonyme du même nom

NotApplicable.java:7: run() in cannot be applied to (int) 
       run(42); 
       ^
1 error 

La question est pourquoi? Pourquoi javac pense que j'appelle run(), et ne trouve pas run (int bar)? Il a correctement appelé foo (int bar). Pourquoi dois-je utiliser NotApplicable.this.run (42) ;? Est-ce un bug?

public class NotApplicable { 

    public NotApplicable() { 
     new Runnable() { 
      public void run() { 
       foo(42); 
       run(42); 
       // uncomment below to fix 
       //NotApplicable.this.run(42); 
      } 
     }; 
    } 

    private void run(int bar) { 
    } 

    public void foo(int bar) { 
    } 
} 

Répondre

16

L'explication du comportement de votre exemple de code est que this est définie comme étant la classe dont vous êtes "le plus" à l'intérieur. Dans ce cas, vous êtes "la plupart" à l'intérieur de la classe interne anonyme qui sous-classe runnable et il n'y a aucune méthode qui correspond run(int). Pour élargir votre recherche, indiquez le this que vous souhaitez utiliser en indiquant NotApplicable.this.run(42).

Le jvm évaluera comme suit:

this -> en cours d'exécution instance de Runnable avec la méthode run()

NotApplicable.this -> exécution instance de NotApplicable avec la méthode run(int)

actuellement Le compilateur recherchera l'arbre d'imbrication pour la première méthode qui correspond au nom de la méthode. -Merci à DJClayworth pour cette clarification

La classe interne anonyme n'est pas une sous-classe de la classe externe. En raison de cette relation, la classe interne et la classe externe doivent être capables d'avoir une méthode avec exactement la même signature et le bloc de code le plus profond devrait être capable d'identifier la méthode qu'il veut exécuter.

public class Outer{ 

    public Outer() { 
     new Runnable() { 
      public void printit() { 
       System.out.println("Anonymous Inner"); 
      } 
      public void run() { 
       printit(); // prints "Anonymous Inner" 
       this.printit(); //prints "Anonymous Inner" 

       // would not be possible to execute next line without this behavior 
       Outer.this.printit(); //prints "Outer" 
      } 
     }; 
    } 

    public void printit() { 
     System.out.println("Outer"); 
    } 
} 
+0

Vous n'expliquez pas pourquoi foo (int bar) est correctement appelé. – Pyrolistical

+2

Cette réponse est correcte, à l'exception de la partie sur "Ce comportement serait exposé même si les deux méthodes n'étaient pas nommées 'run'". Le compilateur recherchera l'arbre d'imbrication pour la première méthode qui correspond au nom de la méthode. – DJClayworth

0

C'est parce que run est en cours de re-déclarée lorsque vous entrez dans le champ new Runnable() {}. Toutes les liaisons précédentes à exécuter deviennent inaccessibles. Il est comme si vous faisiez ceci:

import java.util.*; 

public class tmp 
{ 
    private int x = 20; 
    public static class Inner 
    { 
     private List x = new ArrayList(); 
     public void func() 
     { 
      System.out.println(x + 10); 
     } 
    } 

    public static void main(String[] args) 
    { 
    (new Inner()).func(); 
    } 
} 

Le compilateur ne cherchera pas quelque chose qui correspond au type de x tout le chemin jusqu'à la pile de portée, il vous reste plus qu'à mettre un terme quand il trouve les premières références et voit que les types sont incompatibles.

REMARQUE: Ce n'est pas comme si elle ne pouvait pas faire ... il est juste que, pour préserver votre propre santé mentale, il a été décidé qu'il ne devrait pas.

+0

mais les deux fonctions d'exécution n'ont pas la même signature. C'est en surcharge. Pas prioritaire. –

+0

apparemment, il l'écrase. Si ce n'était pas le cas, cela le surchargerait correctement. – Claudiu

+1

Il se cache pas de surcharge. – DJClayworth

1

Pour autant que je me rappelle les règles de sélection d'une méthode pour exécuter entre les classes imbriquées sont à peu près les mêmes que les règles de sélection d'une méthode dans un arbre d'héritage. Cela veut dire que ce que nous recevons ici ne surcharge pas, c'est la dissimulation. La différence entre ceux-ci est cruciale pour comprendre les méthodes en héritage. Si votre Runnable a été déclaré en tant que sous-classe, la méthode run() masquerait la méthode run (int) dans le parent. Tout appel à exécuter (...) essaierait d'exécuter celui sur Runnable, mais échouerait s'il ne pouvait pas correspondre à des signatures. Puisque foo n'est pas déclaré dans l'enfant, alors celui sur le parent est appelé.

Le même principe se passe ici. Rechercher des références à "méthode de dissimulation" et il devrait être clair.

Questions connexes