java - tipos - ¿Cómo accedo a métodos privados y miembros de datos privados a través de la reflexión?
modificadores de acceso java pdf (6)
Sé que podemos acceder al constructor privado a través de la reflexión como @Sanjay T. Sharma mencionó en su respuesta a mi pregunta: ¿"instanceof Void" siempre devuelve falso?
Sin embargo, @duffymo said :
puede acceder a todo privado con la reflexión: métodos, constructores, miembros de datos, todo.
- ¿Cómo puedo acceder a los métodos privados y a los miembros de datos privados?
- ¿Es posible acceder a la variable local a través de la reflexión?
- ¿Hay alguna manera de evitar que alguien acceda a constructores privados, métodos y miembros de datos?
- Usando el método que se muestra en la respuesta a la que vinculó: setAccessible(true) , que es un método de la superclase de Campo, Constructor y Método.
- No.
- No, a menos que el código se ejecute en una JVM que usted controle, donde instale un administrador de seguridad. Pero si le das a alguien un archivo jar y usa las clases de este archivo jar, podrá acceder a todo.
1) ¿Cómo puedo acceder a los métodos privados y a los miembros de datos privados?
Puedes hacerlo con un poco de ayuda del método setAccessible(true)
:
class Dummy{
private void foo(){
System.out.println("hello foo()");
}
private int i = 10;
}
class Test{
public static void main(String[] args) throws Exception {
Dummy d = new Dummy();
/*--- [INVOKING PRIVATE METHOD] ---*/
Method m = Dummy.class.getDeclaredMethod("foo");
//m.invoke(d); // Exception java.lang.IllegalAccessException
m.setAccessible(true);//Abracadabra
m.invoke(d); // Now it''s OK
/*--- [GETING VALUE FROM PRIVATE FIELD] ---*/
Field f = Dummy.class.getDeclaredField("i");
//System.out.println(f.get(d)); // Not accessible now
f.setAccessible(true); // Abracadabra
System.out.println(f.get(d)); // Now it''s OK
/*--- [SETTING VALUE OF PRIVATE FIELD] ---*/
Field f2 = Dummy.class.getDeclaredField("i");
//f2.set(d,20); // Not accessible now
f2.setAccessible(true); // Abracadabra
f2.set(d, 20); // Now it''s OK
System.out.println(f2.get(d));
}
}
2) ¿Es posible acceder a una variable local a través de la reflexión?
No. No se puede acceder a las variables locales fuera de un bloque en el que se crearon (alguien podría decir que puede asignar dicha variable a un campo como field = localVariable;
y luego acceder a dicho campo a través de la reflexión, pero de esta manera estaremos accediendo al valor , no a la variable ).
3) ¿Hay alguna manera de evitar que alguien acceda a constructores privados, métodos y miembros de datos?
Creo que para constructors
o methods
puedes usar stacktrace para verificar si fue invocado por Reflection
.
Para los campos no puedo encontrar una solución para evitar el acceso a ellos a través de la reflexión.
[ADVERTENCIA: Esto no está aprobado por nadie. Lo escribí inspirado por tu pregunta.]
class Dummy {
private void safeMethod() {
StackTraceElement[] st = new Exception().getStackTrace();
// If a method was invoked by reflection, the stack trace would be similar
// to something like this:
/*
java.lang.Exception
at package1.b.Dummy.safeMethod(SomeClass.java:38)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
-> at java.lang.reflect.Method.invoke(Method.java:601)
at package1.b.Test.main(SomeClass.java:65)
*/
//5th line marked by "->" is interesting one so I will try to use that info
if (st.length > 5 &&
st[4].getClassName().equals("java.lang.reflect.Method"))
throw new RuntimeException("safeMethod() is accessible only by Dummy object");
// Now normal code of method
System.out.println("code of safe method");
}
// I will check if it is possible to normally use that method inside this class
public void trySafeMethod(){
safeMethod();
}
Dummy() {
safeMethod();
}
}
class Dummy1 extends Dummy {}
class Test {
public static void main(String[] args) throws Exception {
Dummy1 d1 = new Dummy1(); // safeMethod can be invoked inside a superclass constructor
d1.trySafeMethod(); // safeMethod can be invoked inside other Dummy class methods
System.out.println("-------------------");
// Let''s check if it is possible to invoke it via reflection
Method m2 = Dummy.class.getDeclaredMethod("safeMethod");
// m.invoke(d);//exception java.lang.IllegalAccessException
m2.setAccessible(true);
m2.invoke(d1);
}
}
Salida del método principal de Test
:
code of safe method
code of safe method
-------------------
Exception in thread "main" java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at package1.b.Test.main(MyClass2.java:87)
Caused by: java.lang.RuntimeException: method safeMethod() is accessible only by Dummy object
at package1.b.Dummy.safeMethod(MyClass2.java:54)
... 5 more
Ejemplo como a continuación:
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
class Test
{
private int a = 5; // Private data member
private void call(int n) // Private method
{
System.out.println("in call() n: " + n);
}
}
public class Sample
{
public static void main(String args[]) throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchFieldException
{
Class c = Class.forName("Test");
Object obj = c.newInstance();
//---- Accessing a private method
Method m=c.getDeclaredMethod("call",new Class[]{int.class});
m.setAccessible(true);
m.invoke(obj,7);
//---- Accessing a private data member
Field d = c.getDeclaredField("a");
d.setAccessible(true);
System.out.println(d.getInt(obj));
}
}
Para responder a su tercera pregunta:
- ¿Hay alguna manera de evitar que alguien acceda a constructores privados, métodos y miembros de datos?
Responder:
Sí, puede restringir el acceso (puede lanzar una excepción cuando alguien intente acceder a su constructor / método / datos privados)
Consulte el siguiente ejemplo:
******JavaSingleton Class******
package server;
public class JavaSingleton {
private static final JavaSingleton INSTANCE = new JavaSingleton();
private JavaSingleton() {
if (INSTANCE != null) {
throw new IllegalStateException("Inside JavaSingleton(): JavaSingleton " +
"instance already created.");
}
System.out.println("Inside JavaSingleton(): Singleton instance is being created.");
}
public static final JavaSingleton getInstance() {
return INSTANCE;
}
}
***Listing 2: JavaSingleton client***
import server.JavaSingleton;
import java.lang.reflect.*;
public class TestSingleton {
public static void main(String[] args) throws ReflectiveOperationException {
System.out.println("Inside main(): Getting the singleton instance using getInstance()...");
JavaSingleton s = JavaSingleton.getInstance();
System.out.println("Inside main(): Trying to use reflection to get another instance...");
Class<JavaSingleton> clazz = JavaSingleton.class;
Constructor<JavaSingleton> cons = clazz.getDeclaredConstructor();
cons.setAccessible(true);
JavaSingleton s2 = cons.newInstance();
}
}
Output:
C:/singleton>java TestSingleton
Inside main(): Getting the singleton instance using getInstance()...
Inside JavaSingleton(): Singleton instance is being created.
Inside main(): Trying to use reflection to get another instance...
Exception in thread "main" java.lang.reflect.InvocationTargetException
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)
at java.lang.reflect.Constructor.newInstance(Unknown Source)
at TestSingleton.main(TestSingleton.java:13)
Caused by: java.lang.IllegalStateException: Inside JavaSingleton(): JavaSingleton instance already created.
at server.JavaSingleton.<init>(JavaSingleton.java:7)
... 5 more
Este ejemplo fue para una clase singleton (comprobando el constructor), pero aún puede implementar esta lógica para los métodos privados que desea evitar el acceso de otras clases.
En este caso, también declarará una instancia estática y verificará su valor en el método privado y arrojará un error en caso de cualquier valor no deseado.
Para acceder a un campo privado , deberá llamar al Class.getDeclaredField(String name)
o enter code here
. Verifique este código simple:
public class PrivateObject {
private String privateString = null;
public PrivateObject(String privateString) {
this.privateString = privateString;
}
}
PrivateObject privateObject = new PrivateObject("The Private Value");
Field privateStringField = PrivateObject.class.
getDeclaredField("privateString");
privateStringField.setAccessible(true);
String fieldValue = (String) privateStringField.get(privateObject);
System.out.println("fieldValue = " + fieldValue
Para acceder a un método privado , deberá llamar al método Class.getDeclaredMethod (String name, Class [] parameterTypes) o Class.getDeclaredMethods ().
Verifique este código simple:
public class PrivateObject {
private String privateString = null;
public PrivateObject(String privateString) {
this.privateString = privateString;
}
private String getPrivateString(){
return this.privateString;
}
}
PrivateObject privateObject = new PrivateObject("The Private Value");
Method privateStringMethod = PrivateObject.class.
getDeclaredMethod("getPrivateString", null);
privateStringMethod.setAccessible(true);
String returnValue = (String)
privateStringMethod.invoke(privateObject, null);
System.out.println("returnValue = " + returnValue);
Lea los detalles en http://tutorials.jenkov.com/java-reflection/private-fields-and-methods.html
Area s=(Area)c.newInstance();
s.setRadius(10);
System.out.println("Area: "+s.calculateArea(4));
Method m[]=c.getDeclaredMethods();
Constructor c1[]=c.getConstructors();
for(int i=0;i<m.length;i++)
System.out.println(""+m[i]);
for(int i=0;i<c1.length;i++)
System.out.println(""+c1[i]);