simbologia relacionales prioridad operadores logicos ejemplos condicionales comparacion aritmeticos java class reflection field private

relacionales - prioridad de operadores en java



¿Cómo leer el valor de un campo privado de una clase diferente en Java? (10)

Como lo menciona oxbow_lakes, puede usar la reflexión para sortear las restricciones de acceso (suponiendo que su SecurityManager le permita).

Dicho esto, si esta clase está tan mal diseñada que te hace recurrir a este tipo de piratería, tal vez deberías buscar una alternativa. Seguro que este pequeño truco podría estar ahorrando algunas horas ahora, pero ¿cuánto te costará en el futuro?

Tengo una clase mal diseñada en un JAR terceros y necesito acceder a uno de sus campos privados . Por ejemplo, ¿por qué debería elegir un campo privado si es necesario?

class IWasDesignedPoorly { private Hashtable stuffIWant; } IWasDesignedPoorly obj = ...;

¿Cómo puedo usar la reflexión para obtener el valor de stuffIWant ?


La reflexión no es la única forma de resolver su problema (que es acceder a la funcionalidad / comportamiento privado de una clase / componente)

Una solución alternativa es extraer la clase del archivo .jar, descompilarlo utilizando (por ejemplo) Jode o Jad , cambiar el campo (o agregar un elemento de acceso) y recompilarlo contra el archivo .jar original. Luego, coloque la nueva .class delante de .jar en la ruta de clase, o vuelva a insertarla en el .jar . (la utilidad jar le permite extraer y volver a insertar en un .jar existente)

Como se señala a continuación, esto resuelve el problema más amplio de acceder / cambiar el estado privado en lugar de simplemente acceder / cambiar un campo.

Esto requiere que el .jar no esté firmado, por supuesto.


Necesitas hacer lo siguiente:

private static Field getField(Class<?> cls, String fieldName) { for (Class<?> c = cls; c != null; c = c.getSuperclass()) { try { final Field field = c.getDeclaredField(fieldName); field.setAccessible(true); return field; } catch (final NoSuchFieldException e) { // Try parent } catch (Exception e) { throw new IllegalArgumentException( "Cannot access field " + cls.getName() + "." + fieldName, e); } } throw new IllegalArgumentException( "Cannot find field " + cls.getName() + "." + fieldName); }


Otra opción que aún no se ha mencionado: usar Groovy . Groovy le permite acceder a variables de instancia privadas como un efecto secundario del diseño del lenguaje. Ya sea que tenga o no un captador para el campo, solo puede usar

def obj = new IWasDesignedPoorly() def hashTable = obj.getStuffIWant()


Para acceder a los campos privados, debe obtenerlos de los campos declarados de la clase y luego hacerlos accesibles:

Field f = obj.getClass().getDeclaredField("stuffIWant"); //NoSuchFieldException f.setAccessible(true); Hashtable iWantThis = (Hashtable) f.get(obj); //IllegalAccessException

EDITAR : como ha sido comentado por aperkins , ambos accediendo al campo, configurándolo como accesible y recuperando el valor arrojarán Exception , aunque las únicas excepciones marcadas que debe tener en cuenta están comentadas anteriormente.

La NoSuchFieldException se NoSuchFieldException si usted solicita un campo con un nombre que no corresponde a un campo declarado.

obj.getClass().getDeclaredField("misspelled"); //will throw NoSuchFieldException

La IllegalAccessException se lanzaría si el campo no fuera accesible (por ejemplo, si es privado y no se ha hecho accesible a través de perder la línea f.setAccessible(true) .

Las RuntimeException s que pueden ser lanzadas son SecurityException s (si SecurityManager de JVM no le permitirá cambiar la accesibilidad de un campo), o IllegalArgumentException s, si intenta acceder al campo en un objeto que no sea del tipo de clase del campo:

f.get("BOB"); //will throw IllegalArgumentException, as String is of the wrong type


Prueba FieldUtils desde apache commons-lang3:

FieldUtils.readField(object, fieldName, true);


Si usa Spring, ReflectionTestUtils proporciona algunas herramientas útiles que ayudan aquí con un mínimo esfuerzo. Se describe como "para uso en escenarios de pruebas de unidad e integración" . También hay una clase similar llamada ReflectionUtils pero esto se describe como "Solo para uso interno" . Consulte esta respuesta para obtener una interpretación de lo que esto significa.

Para abordar el ejemplo publicado:

Hashtable iWantThis = (Hashtable)ReflectionTestUtils.getField(obj, "stuffIWant");


Solo una nota adicional sobre la reflexión: En algunos casos especiales, he observado que cuando existen varias clases con el mismo nombre en diferentes paquetes, la reflexión que se usa en la respuesta superior puede no seleccionar la clase correcta del objeto. Entonces, si sabe qué es el package.class del objeto, entonces es mejor acceder a sus valores de campo privado de la siguiente manera:

org.deeplearning4j.nn.layers.BaseOutputLayer ll = (org.deeplearning4j.nn.layers.BaseOutputLayer) model.getLayer(0); Field f = Class.forName("org.deeplearning4j.nn.layers.BaseOutputLayer").getDeclaredField("solver"); f.setAccessible(true); Solver s = (Solver) f.get(ll);

(Esta es la clase de ejemplo que no me funcionó)


Usando el Reflection en Java , puede acceder a todos los campos y métodos private/public de una clase a otra. Pero según la documentation Oracle en la sección de inconvenientes , recomendaron que:

"Dado que la reflexión permite que el código realice operaciones que serían ilegales en el código no reflexivo, como el acceso a campos y métodos privados, el uso de la reflexión puede producir efectos secundarios inesperados, que pueden hacer que el código sea disfuncional y puede destruir la portabilidad. Código reflexivo rompe las abstracciones y, por lo tanto, puede cambiar el comportamiento con las actualizaciones de la plataforma "

Aquí está el siguiente código para demostrar conceptos básicos de Reflexión.

Reflection1.java

public class Reflection1{ private int i = 10; public void methoda() { System.out.println("method1"); } public void methodb() { System.out.println("method2"); } public void methodc() { System.out.println("method3"); } }

Reflection2.java

import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class Reflection2{ public static void main(String ar[]) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { Method[] mthd = Reflection1.class.getMethods(); // for axis the methods Field[] fld = Reflection1.class.getDeclaredFields(); // for axis the fields // Loop for get all the methods in class for(Method mthd1:mthd) { System.out.println("method :"+mthd1.getName()); System.out.println("parametes :"+mthd1.getReturnType()); } // Loop for get all the Field in class for(Field fld1:fld) { fld1.setAccessible(true); System.out.println("field :"+fld1.getName()); System.out.println("type :"+fld1.getType()); System.out.println("value :"+fld1.getInt(new Reflaction1())); } } }

Espero que ayude.


Utilice el marco de Soot Java Optimization para modificar directamente el bytecode. http://www.sable.mcgill.ca/soot/

Soot está completamente escrito en Java y funciona con nuevas versiones de Java.