2012-05-29 15 views
12

Esiste una sintassi Java per accedere ai nuovi metodi definiti all'interno di classi interne anonime dalla classe esterna? So che ci possono essere varie soluzioni alternative, ma mi chiedo se esista una sintassi speciale?Posso accedere a nuovi metodi nella classe interna anonima con qualche sintassi?

Per esempio

class Outer { 

    ActionListener listener = new ActionListener() { 

     @Override 
     void actionPerformed(ActionEvent e) { 
      // do something 
     } 

     // method is public so can be accessible 
     public void MyGloriousMethod() { 
      // viva! 
     } 

    }; 

    public void Caller() { 
     listener.MyGloriousMethod(); // does not work! 
    } 


} 

mia soluzione OWN

Mi sono appena trasferito tutti i metodi e membri fino alla classe esterna.

risposta

18

Una volta che l'istanza di classe anonima è stata inoltrata implicitamente nel tipo named, non può essere richiamata perché non esiste un nome per il tipo anonimo. È possibile accedere ai membri aggiuntivi della classe interna anonima tramite this all'interno della classe, nell'espressione immediata dopo l'espressione e il tipo può essere dedotto e restituito tramite una chiamata di metodo.

Object obj = new Object() { 
    void fn() { 
     System.err.println("fn"); 
    } 
    @Override public String toString() { 
     fn(); 
     return ""; 
    } 
}; 
obj.toString(); 



new Object() { 
    void fn() { 
     System.err.println("fn"); 
    } 
}.fn(); 


identity(new Object() { 
    void fn() { 
     System.err.println("fn"); 
    } 
}).fn(); 
... 
private static <T> T identity(T value) { 
    return value; 
} 
+0

Wow! Conosci il caso in cui è possibile chiamare un membro della classe anonimo! –

3

Il chiamante conosce listener come ActionListener e quindi non sa nulla di quel nuovo metodo. Penso che l'unico modo per farlo (oltre al fare ginnastica riflessiva, che davvero vanificherebbe lo scopo di usare una classe anonima, ovvero la scorciatoia/semplicità) è semplicemente la sottoclasse ActionListener e non usare una classe anonima.

+0

Yup. La soluzione qui è ... non renderlo anonimo. –

+0

@Louis se non lo faccio anonimo, non otterrò dall'economia della sintassi. Dovrò creare una classe e un'istanza di essa. –

+0

@SuzanCioc: crei anche una classe e un'istanza con il codice corrente. La classe è anonima, ma è l'unica differenza. –

1

No, non è possibile. Dovresti lanciare ActionListener nel suo vero nome di sottoclasse, ma dal momento che è anonimo, non ha un nome.

+0

Ma potrebbero creare alcune parole chiave come 'listener.that.MyGloriousMethod()' o '((Anonimo) listener) .MyGloriousMethod()' poiché la classe anonima non è in realtà anonimo per JVM ma solo il suo nome è sconosciuto al programmatore e quindi il problema è solo denotarlo in qualche modo. –

+0

Avrebbero potuto immaginare qualcosa, ma non l'hanno fatto, perché è già fattibile molto semplicemente: creando una classe interiore non anonima. –

1

Il modo giusto per farlo sta usando riflessione:

import java.lang.reflect.InvocationTargetException; 

public class MethodByReflectionTest { 

    public static void main(String[] args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException { 

     Object obj = new Object(){ 
      public void print(){ 
       System.out.println("Print executed."); 
      } 
     }; 

     obj.getClass().getMethod("print", null).invoke(obj, null); 
    } 
} 

È possibile controllare qui: How do I invoke a Java method when given the method name as a string?

5

Uno studente nella mia classe ha chiesto il nostro professore se questo potrebbe essere fatto l'altro giorno . Ecco quello che ho scritto come prova fresco di concetto che si può fare, anche se non vale la pena, in realtà è possibile ed ecco come:

public static void main(String[] args){ 

    //anonymous inner class with method defined inside which 
    //does not override anything 
    Object o = new Object() 
    { 
     public int test = 5; 
     public void sayHello() 
     { 
      System.out.println("Hello World"); 
     } 
    }; 

    //o.sayHello();//Does not work 

    try 
    { 
     Method m = o.getClass().getMethod("sayHello"); 
     Field f = o.getClass().getField("test"); 
     System.out.println(f.getInt(o)); 
     m.invoke(o); 
    } catch (Exception e) 
    { 
     e.printStackTrace(); 
    } 
} 

Facendo uso della class Metodo di Java possiamo invocare un metodo passando il valore della stringa e i parametri del metodo. La stessa cosa può essere fatta con i campi.

Ho pensato che sarebbe stato bello condividere questo!

0

Sì, è possibile accedere al metodo vedere l'esempio di seguito in caso di dubbio si prega di commentare

package com; 
interface A 
{ 
    public void display(); 
} 
public class Outer { 
    public static void main(String []args) 
    { 
     A a=new A() { 
     @Override 
     public void display() { 
      System.out.println("Hello"); 
     } 
    }; 
     a.display(); 
    } 
    } 
Problemi correlati