tipos superclase sirve significa que para metodo llamar herencia heredado ejemplos como comando clase java reflection override superclass

sirve - superclase java



Cómo llamar a un método de superclase utilizando la reflexión de Java (7)

Tengo dos clases.

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

Tengo una instancia de B. ¿Cómo puedo llamar a A.method () desde b? Básicamente, el mismo efecto que llamar a super.method () desde 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);

Pero el código anterior todavía invocará B.method ()


Basándome en la respuesta de @java4script, noté que obtienes una IllegalAccessException si tratas de hacer este truco desde fuera de la subclase (es decir, donde normalmente super.toString() llamando a super.toString() para empezar). El método in permite omitir esto solo en algunos casos (como cuando llama desde el mismo paquete que Base y Sub ). La única solución alternativa que encontré para el caso general es un truco extremo (y claramente no portable):

package p; public class Base { @Override public String toString() { return "Base"; } } package p; public class Sub extends Base { @Override public String toString() { 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(String[] 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, "toString", MethodType.methodType(String.class), Sub.class); System.out.println(h1.invoke(new Sub())); } }

impresión

Sub Base


No es posible. El envío de métodos en Java siempre considera el tipo de tiempo de ejecución del objeto, incluso cuando se usa el reflejo. Vea el javadoc para Method.invoke ; en particular, esta sección:

Si el método subyacente es un método de instancia, se invoca utilizando la búsqueda de métodos dinámicos tal como se documenta en la Especificación del lenguaje Java, segunda edición, sección 15.12.4.4; en particular, se producirá una anulación basada en el tipo de tiempo de ejecución del objeto de destino.


No puede, necesitará una instancia de la superclase debido a la forma en que el envío de métodos funciona en Java.

Podrías probar algo como esto:

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( String ... args ) throws Exception { A b = new B(); b.method(); b.getClass() .getSuperclass() .getMethod("method", new Class[]{} ) .invoke( b.getClass().getSuperclass().newInstance() ,new Object[]{} ); } }

Pero lo más probable es que no tenga sentido, porque perderá los datos en b .


No puedes hacer eso. Significaría que el polimorfismo no está funcionando.

Necesitas una instancia de A Puede crear uno por superclass.newInstance() y luego transferir todos los campos con algo como BeanUtils.copyProperties(..) (de commons-beanutils). Pero eso es un ''hack'': en su lugar, debes arreglar tu diseño para que no lo necesites.


No sé cómo hacerlo en el caso en que quieras hacer el truco para las bibliotecas incluidas, porque la reflexión no funciona, pero para mi propio código, haría esta solución simple:

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

Para casos simples, esto está bien, para algunas invocación automática no tanto. Por ejemplo, cuando tienes una cadena

A1 super A2 super A3 ... super An

de heredar clases, reemplazando todo un método m. Entonces, invocar m desde A1 en una instancia de An requeriría demasiada mala codificación :-)


Puede crear una secuencia de código de bytes usando un puntero diferente antes de invocar docs.oracle.com/javase/specs/jvms/se7/html/… .

Llamar al método super.toString () de cualquier objeto es como:

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

De esta forma, es posible crear una clase anónima que contenga el objeto necesario.


Si está utilizando JDK7, puede usar MethodHandle para lograr esto:

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