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

Resuelto Frank Krueger asked hace 15 años • 14 respuestas

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

class IWasDesignedPoorly {
    private Hashtable stuffIWant;
}

IWasDesignedPoorly obj = ...;

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

Frank Krueger avatar Jul 29 '09 02:07 Frank Krueger
Aceptado

Para acceder a 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 lo comentó aperkins , acceder al campo, configurarlo como accesible y recuperar el valor puede generar mensajes de correo electrónico Exception, aunque las únicas excepciones marcadas que debe tener en cuenta se comentan anteriormente.

Se NoSuchFieldExceptionarrojaría si solicitara un campo con un nombre que no correspondiera a un campo declarado.

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

Se IllegalAccessExceptionlanzaría si el campo no fuera accesible (por ejemplo, si es privado y no se ha hecho accesible al omitir la f.setAccessible(true)línea).

Los RuntimeExceptionmensajes de correo electrónico que se pueden generar son SecurityExceptions (si la JVM SecurityManagerno le permite cambiar la accesibilidad de un campo) o IllegalArgumentExceptions, si intenta acceder al campo en un objeto que no es del tipo de clase del campo:

f.get("BOB"); //will throw IllegalArgumentException, as String is of the wrong type
oxbow_lakes avatar Jul 28 '2009 19:07 oxbow_lakes

Pruebe FieldUtilsdesde Apache commons-lang3 :

FieldUtils.readField(object, fieldName, true);

PD: En mi opinión, la reflexión es mala .

yegor256 avatar Apr 25 '2014 07:04 yegor256

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 .jar, descompilarla usando (digamos) Jode o Jad , cambiar el campo (o agregar un descriptor de acceso) y volver a compilarlo con el .jar original. Luego coloque el nuevo .class delante del .jaren el classpath, o reinsértelo en el .jar. (la utilidad jar le permite extraer y reinsertar en un .jar existente)

Como se indica 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, .jarpor supuesto, que no esté firmado.

Brian Agnew avatar Jul 28 '2009 21:07 Brian Agnew

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

def obj = new IWasDesignedPoorly()
def hashTable = obj.getStuffIWant()
lucas avatar Jan 19 '2010 14:01 lucas