Comment appeler une méthode de super classe en utilisant la reflection Java

J’ai deux cours.

public class A { public Object method() {...} } public class B extends A { @Override public Object method() {...} } 

J’ai une instance de B. Comment appeler A.method () à partir de b? Fondamentalement, le même effet que d’appeler super.method () de B.

 B b = new B(); Class superclass = b.getClass().getSuperclass(); Method method = superclass.getMethod("method", ArrayUtils.EMPTY_CLASS_ARRAY); Object value = method.invoke(obj, ArrayUtils.EMPTY_OBJECT_ARRAY); 

Mais le code ci-dessus invoquera toujours B.method ()

Si vous utilisez JDK7, vous pouvez utiliser MethodHandle pour y parvenir:

 public class Test extends Base { public static void main(Ssortingng[] args) throws Throwable { MethodHandle h1 = MethodHandles.lookup().findSpecial(Base.class, "toSsortingng", MethodType.methodType(Ssortingng.class), Test.class); MethodHandle h2 = MethodHandles.lookup().findSpecial(Object.class, "toSsortingng", MethodType.methodType(Ssortingng.class), Test.class); System.out.println(h1.invoke(new Test())); // outputs Base System.out.println(h2.invoke(new Test())); // outputs Base } @Override public Ssortingng toSsortingng() { return "Test"; } } class Base { @Override public Ssortingng toSsortingng() { return "Base"; } } 

Ce n’est pas possible. La méthode dispatching en Java considère toujours le type d’exécution de l’object, même en utilisant la reflection. Voir le javadoc pour Method.invoke ; en particulier, cette section:

Si la méthode sous-jacente est une méthode d’instance, elle est appelée à l’aide de la recherche par méthode dynamic, comme indiqué dans la spécification du langage Java, deuxième édition, section 15.12.4.4; en particulier, une substitution basée sur le type d’exécution de l’object cible se produira.

En me basant sur la réponse de @ java4script, j’ai remarqué que vous obtenez une IllegalAccessException si vous essayez de faire cette astuce en dehors de la sous-classe (c’est-à-dire où vous appelleriez normalement super.toSsortingng() ). La méthode in vous permet de l’ignorer uniquement dans certains cas (par exemple lorsque vous appelez du même package que Base et Sub ). La seule solution de contournement que j’ai trouvée pour le cas général est un hack extrême (et clairement non portable):

 package p; public class Base { @Override public Ssortingng toSsortingng() { return "Base"; } } package p; public class Sub extends Base { @Override public Ssortingng toSsortingng() { return "Sub"; } } import p.Base; import p.Sub; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; import java.lang.reflect.Field; public class Demo { public static void main(Ssortingng[] args) throws Throwable { System.out.println(new Sub()); Field IMPL_LOOKUP = MethodHandles.Lookup.class.getDeclaredField("IMPL_LOOKUP"); IMPL_LOOKUP.setAccessible(true); MethodHandles.Lookup lkp = (MethodHandles.Lookup) IMPL_LOOKUP.get(null); MethodHandle h1 = lkp.findSpecial(Base.class, "toSsortingng", MethodType.methodType(Ssortingng.class), Sub.class); System.out.println(h1.invoke(new Sub())); } } 

impression

 Sub Base 

Vous ne pouvez pas, vous aurez besoin d’une instance de la super classe à cause de la façon dont les méthodes de dissortingbution fonctionnent en Java.

Vous pourriez essayer quelque chose comme ça:

 import java.lang.reflect.*; class A { public void method() { System.out.println("In a"); } } class B extends A { @Override public void method() { System.out.println("In b"); } } class M { public static void main( Ssortingng ... args ) throws Exception { A b = new B(); b.method(); b.getClass() .getSuperclass() .getMethod("method", new Class[]{} ) .invoke( b.getClass().getSuperclass().newInstance() ,new Object[]{} ); } } 

Mais très probablement, cela n’a pas de sens, car vous perdrez les données dans b .

Vous ne pouvez pas faire ça. Cela voudrait dire que le polymorphism ne fonctionne pas.

Vous avez besoin d’une instance de A Vous pouvez en créer un par superclass.newInstance() puis transférer tous les champs avec quelque chose comme BeanUtils.copyProperties(..) (à partir de commons-beanutils). Mais c’est un «hack» – vous devriez plutôt réparer votre conception pour que vous n’en ayez pas besoin.

Je ne sais pas comment faire dans le cas où vous voulez faire le tour pour les bibliothèques incluses, parce que la reflection ne fonctionne pas, mais pour mon propre code, je ferais cette solution simple:

 public class A { public Object method() {...} } public class B extends A { @Override public Object method() {...} public Object methodSuper() { return super.method(); } } 

Pour les cas simples, cela ne pose pas de problème, pour une invocation automatique moins. Par exemple, lorsque vous avez une chaîne

 A1 super A2 super A3 ... super An 

d’hériter des classes, toutes remplaçant une méthode m. Invoquer alors m à partir de A1 sur une instance de An nécessiterait trop de mauvais codage 🙂

Vous pouvez créer une séquence de code d’octet en utilisant un pointeur différent avant d’appeler invokespecial .

L’appel de la méthode super.toSsortingng () de n’importe quel object est comme suit:

 ALOAD X ;X = slot of object reference of the object to access INVOKESPECIAL java/lang/Object.toSsortingng ()Ljava/lang/Ssortingng; POP 

Cette façon de créer une classe anonyme contenant l’object nécessaire est possible.