¿Cómo leer el valor de un campo privado de una clase diferente en Java?
Tengo una clase mal diseñada en un tercero JAR
y 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
?
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 NoSuchFieldException
arrojaría si solicitara un campo con un nombre que no correspondiera a un campo declarado.
obj.getClass().getDeclaredField("misspelled"); //will throw NoSuchFieldException
Se IllegalAccessException
lanzarí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 RuntimeException
mensajes de correo electrónico que se pueden generar son SecurityException
s (si la JVM SecurityManager
no le permite cambiar la accesibilidad de un campo) o IllegalArgumentException
s, 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
Pruebe FieldUtils
desde Apache commons-lang3 :
FieldUtils.readField(object, fieldName, true);
PD: En mi opinión, la reflexión es mala .
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 .jar
en 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, .jar
por supuesto, que no esté firmado.
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()