2009-03-13 8 views
2

Je souhaite initialiser un tableau de méthodes Java dans la classe des enfants, comme un champ de classe comme siRéception d'une méthode Java sans utiliser getDeclaredMethod

void callme() {System.out.println("hi!");} 
Method[] actions = new Method[] {&callme,&callme}; 

et appeler toutes les méthodes de ce tableau à la classe mère comme si:

for (meth:actions) {meth.invoke();} 

Cependant je ne peux pas encore trouver un moyen d'initialiser implicitement le tableau des actions, et non par le constructeur. Ce qui suit me donne une erreur due à exception non gérée:

Method[] actions = new Method[] { 
    this.getClass().getDeclaredMethod("count") 
}; 

Comme dit, je ne peux pas attraper l'exception lors de l'initialisation de ce tableau explicitement comme un champ, et non dans le constructeur. Je suis un débutant à la réflexion java, donc c'est probablement une question évidente, mais je n'ai pas trouvé de réponse à cela à google, toute aide serait appréciée.

Merci

P.S. Comme l'a supposé Scott ci-dessous, je "souhaite qu'une super-classe appelle un ensemble spécifique de méthodes définies dans une sous-classe".

+0

Qu'est-ce que la Terre vous essayez de le faire ? –

+0

Comme Scott ci-dessous deviné, j'essaie de "Si vous voulez une superclasse pour appeler un ensemble spécifique de méthodes définies dans une sous-classe" –

Répondre

-2

Créez une méthode statique dans votre classe qui retournera un tableau de méthodes déclarées et traitera correctement les exceptions.

private static Method[] declaredMethods(Class<T> clazz, String methodName) { 
    Method[] result = new Method[1]; 
    try{ 
    result[0] = clazz.getDeclaredMethod(methodName); 
    } catch (NoSuchMethodException nsme) { 
    // respond to the error 
    } catch (SecurityException se) { 
    // Respond to the error 
    } 

    return result; 
} 

Method[] actions = declaredMethods("count"); 
+0

Cela fonctionnerait, mais c'est aussi laid que ... eh bien, aussi laid que Java parfois est ;-) –

+0

Personne ne peut vous empêcher de déclarer la méthode statique declareMethods (Classe clazz, String) dans une classe séparée avec un constructeur privé et masquer tous les détails laids. Encore mieux, vous pouvez utiliser une bibliothèque Apache Commons. –

+0

"Répondre à l'erreur" ??? –

2

Consultez le Apache Commons - Beanutils! C'est comme une enveloppe autour de toute la réflexion qui est très facile à utiliser. Il encapsule l'invocation de méthode, modifie les attributs, les recherches ...

Si vous voulez mettre en dynamique Java, vous devriez jeter un oeil sur les langages JVM dynamiques qui peuvent être utilisés par simple en incluant une bibliothèque .jar! L'un d'eux est Groovy qui contient la syntaxe java et apporte beaucoup de fonctionnalités dynamiques (scripting, prototypage rapide, Meta-Object-Protocol, runtime-repacing, proxies dynamiques ...).

3

Etes-vous sûr que la réflexion est la bonne chose à faire? Normalement une interface avec plusieurs classes anonymes l'implémentant serait un meilleur style.

Vous pouvez écrire un bloc d'initialisation pour pouvoir intercepter l'exception pendant l'initialisation.

Pourquoi n'utilisez-vous pas getMethod()?

0

Ceci devrait fonctionner aussi longtemps que votre méthode est réellement déclarée dans this.getClass(). S'il est hérité, vous devez utiliser Class.getMethod() à la place. Cependant, au lieu d'utiliser des pointeurs de fonction, en java on définirait une interface avec une méthode que l'on veut appeler, et laisserait cette interface être implémentée par l'objet cible.

Pensez également à utiliser ArrayList ou d'autres classes de collection au lieu de tableaux.

3

[Note: Le code ci-dessous n'a pas été compilé, mais devrait faire passer l'idée]

J'écho - ce que vous essayez d'accomplir?

Si vous souhaitez qu'une super-classe appelle un ensemble spécifique de méthodes définies dans une sous-classe, vous pouvez effectuer certaines opérations.

avec la réflexion, je vous recommande d'utiliser des annotations:

1) définir une annotation HeySuperclassCallMe (rétention faire est sûr RUNTIME)

2) annoter les méthodes pour appeler avec HeySuperclassCallMe

@HeySuperclassCallMe public void foo... 

3) dans votre superclasse faire quelque chose comme

for (Method m : getClass().getMethods()) 
    if (m.getAnnotation(HeySuperclassCallMe.class) != null) 
    m.invoke(...) 

C'est un bon moyen de réflexion pour le faire.

Pour non-réflexion (ce qui devrait être un peu plus rapide, mais plus de code):

1) définir une interface qui représente les appels

public interface Call { 
    void go(); 
} 

2) dans votre superclasse, définir un

private List<Call> calls 
protected void addCall(Call call) 

3) dans la sous-classe, en utilisant addCall:

addCall(new Call() {public void go() {foo();}}); 

4) dans les superclasse

for (Call call : calls) 
    call.go(); 
+0

J'ai pensé à la technique d'annotation, mais ce que je n'aime pas c'est que vous ne pouvez pas spécifier la commande. En fait, j'ai finalement fait @UseMessage (order = 0). Ce qui a bien fonctionné, mais est UGLY UGLY UGLY. (et plus difficile à maintenir, car on ne peut pas facilement insérer une méthode entre les deux). –

+0

BTW: Si vous nommez l'attribut "value", vous pouvez l'utiliser sans le nom de l'attribut: @UseMessage (0). Pas que cela aide la commande, cependant. –

0

Je peux dire par vos esperluette que vous pensez en C. Nous n'utilisons pas vraiment pointeurs de fonctions en java.

Généralement, vous n'utilisez pas de réflexion Java pour cela. Comme l'une des autres affiches dit - vous devez créer une interface, et ont des objets mis en œuvre cette interface - soit par directement la mise en œuvre, ou avec un adaptateur ou une classe anonyme:

interface Callable { void callme(); } 

Callable[] foo = new Callable[] { 
    new Callable() { public void callme() {System.out.println("foo!");}}, 
    new Callable() { public void callme() {System.out.println("bar!");}} 
}; 

for(Callable c: foo) { 
    c.callme(); 
}