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

8 minutos de lectura

¿Como leer el valor de un campo privado de una
franco krueger

Tengo una clase mal diseñada en un tercero JAR y necesito acceder a uno de sus privado campos. 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?

¿Como leer el valor de un campo privado de una
oxbow_lakes

Para acceder a los campos privados, debe obtenerlos de la clase declarado campos 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 aperkinstanto acceder al campo, configurarlo como accesible y recuperar el valor puede arrojar Exceptions, aunque el único comprobado las excepciones que debe tener en cuenta se comentan anteriormente.

los NoSuchFieldException se arrojaría si solicita un campo con un nombre que no corresponde a un campo declarado.

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

los IllegalAccessException se lanzaría si el campo no fuera accesible (por ejemplo, si es privado y no se ha hecho accesible al perder el f.setAccessible(true) línea.

los RuntimeExceptions que se pueden lanzar son SecurityExceptions (si la JVM SecurityManager no le permitirá 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

  • ¿Puede explicar los comentarios de excepción? el código se ejecutará pero arrojará excepciones? o el código puede arrojar excepciones?

    – Nir Levy

    28 de julio de 2009 a las 20:34

  • @Nir – No – con toda probabilidad, el código funcionará bien (ya que el SecurityManager predeterminado permitirá cambiar la accesibilidad de los campos), pero debe hacerlo encargarse de excepciones marcadas (ya sea atraparlas o declararlas como relanzado). He modificado un poco mi respuesta. Podría ser bueno para usted escribir un pequeño caso de prueba para jugar y ver qué sucede.

    – oxbow_lakes

    28 de julio de 2009 a las 20:42

  • Lo siento, esta respuesta es confusa para mí. Quizás muestre un ejemplo de manejo de excepciones típico. Parece que las excepciones ocurrirían cuando las clases están conectadas incorrectamente. El ejemplo de código hace que parezca que las excepciones se generarían en las líneas correspondientes.

    – La Fayette

    29 de febrero de 2016 a las 8:33


  • getDeclaredField() no encuentra campos si están definidos en las clases principales; también debe iterar hacia arriba a través de la jerarquía de la clase principal, llamando getDeclaredField() en cada uno, hasta que encuentre una coincidencia (después de lo cual puede llamar setAccessible(true)), o llegas Object.

    – Lucas Hutchison

    13 de febrero de 2017 a las 8:47

  • @legend puede instalar un administrador de seguridad para prohibir dicho acceso. Desde Java 9, no se supone que dicho acceso funcione a través de los límites del módulo (a menos que un módulo esté abierto explícitamente), aunque hay una fase de transición con respecto a la aplicación de las nuevas reglas. Además de eso, requerir un esfuerzo adicional como Reflection siempre marcó la diferencia para los que noprivate campos. Impide el acceso accidental.

    – Holger

    25 de septiembre de 2018 a las 8:30

Tratar FieldUtils de apache commons-lang3:

FieldUtils.readField(object, fieldName, true);

  • Estoy convencido de que podría resolver la mayoría de los problemas del mundo al unir algunos métodos de commons-lang3.

    – Cameron

    5 de agosto de 2015 a las 18:46

  • @yegor ¿por qué Java permite esto? ¿Por qué Java permite acceder a miembros privados?

    -Asif Mushtaq

    24 de abril de 2016 a las 10:52

  • @ yegor256 ¡Aún puedo acceder a miembros privados de C# y C++ también…! ¿Luego? ¿Todos los creadores de idiomas son débiles?

    -Asif Mushtaq

    28 de abril de 2016 a las 15:04

  • @UnKnown java no lo hace. Hay dos cosas diferentes: lenguaje java y java como máquina virtual java. Este último opera en bytecode. Y hay bibliotecas para manipular eso. Entonces, el lenguaje Java no le permite usar campos privados fuera del alcance o no permite mutar las referencias finales. Pero es posible hacer eso usando la herramienta. Que resulta que está dentro de la biblioteca estándar.

    – evgenii

    7 de agosto de 2016 a las 10:22

  • @UnKnown una de las razones es que Java no tiene acceso de “amigo” para habilitar el acceso al campo solo mediante un marco de infraestructura como DI, ORM o serializador XML/JSON. Dichos marcos necesitan acceso a campos de objetos para serializar o inicializar correctamente el estado interno de un objeto, pero es posible que aún necesite una aplicación adecuada de encapsulación en tiempo de compilación para su lógica comercial.

    – Iván Gamal

    21 de diciembre de 2016 a las 16:51

¿Como leer el valor de un campo privado de una
Brian Agnew

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, cambie el campo (o agregue un descriptor de acceso) y vuelva a compilarlo contra el .jar original. Luego coloque la nueva .class delante de la .jar en el classpath, o reinsértelo en el .jar. (la utilidad jar le permite extraer y volver a insertar 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 la .jar sin firmar, por supuesto.

  • De esta manera será bastante doloroso para un campo simple.

    – Valentín Rocher

    29 de julio de 2009 a las 8:30

  • Estoy en desacuerdo. Le permite no solo acceder a su campo, sino también cambiar la clase si es necesario si acceder al campo resulta no ser suficiente.

    – Brian Agnew

    29 de julio de 2009 a las 8:33

  • Entonces tienes que hacer eso de nuevo. ¿Qué sucede si el contenedor se actualiza y usa la reflexión para un campo que ya no existe? Es exactamente el mismo problema. Solo tienes que administrarlo.

    – Brian Agnew

    23 de noviembre de 2012 a las 8:17


  • Estoy asombrado de cuánto se vota negativamente dado que a) se destaca como una alternativa práctica b) se adapta a escenarios en los que cambiar la visibilidad de un campo no es suficiente

    – Brian Agnew

    27 de diciembre de 2012 a las 9:16


  • @BrianAgnew tal vez sea solo semántico, pero si nos atenemos a la pregunta (usar la reflexión para leer un campo privado), no usar la reflexión es inmediatamente una autocontradicción. Pero estoy de acuerdo en que proporciona acceso al campo … pero aún así el campo ya no es privado, así que nuevamente no nos limitamos a “leer un campo privado” de la pregunta. Desde otro ángulo, la modificación de .jar puede no funcionar en algunos casos (jar firmado), debe realizarse cada vez que se actualiza el jar, requiere una manipulación cuidadosa del classpath (que es posible que no controle por completo si se ejecuta en un contenedor de aplicaciones), etc.

    – Rémi Morin

    24/02/2014 a las 20:58

1646965690 39 ¿Como leer el valor de un campo privado de una
lucas

Otra opción que aún no se ha mencionado: usar maravilloso. Groovy te permite acceder a variables de instancias privadas como un 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()

1646965691 945 ¿Como leer el valor de un campo privado de una
simiente

Utilizando el Reflexión en Java puedes acceder a todos los private/public campos y métodos de una clase a otra. Pero según el Oráculo documentación en la sección 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 acceder a campos y métodos privados, el uso de la reflexión puede generar efectos secundarios inesperados, lo que puede 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án las siguientes instantáneas de código para demostrar los conceptos básicos de Reflexión

Reflexión1.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");
    }

}

Reflexión2.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

1646965691 564 ¿Como leer el valor de un campo privado de una
Laurence Gonsalves

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

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

1646965692 458 ¿Como leer el valor de un campo privado de una
pcpratts

Utilice el marco de optimización de Soot Java para modificar directamente el código de bytes.
http://www.sable.mcgill.ca/hollín/

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

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad