it-swarm.com.de

Wie kann ich über Reflection auf private Methoden und private Datenmitglieder zugreifen?

Ich weiß, dass wir über Reflection auf den privaten Konstruktor zugreifen können, als @Sanjay T. Sharma in seiner Antwort auf meine Frage erwähnt: Gibt "instanceof Void" immer "false" zurück?

@duffymosagte :

sie können mit Reflektion auf alles private zugreifen - Methoden, Konstruktoren, Datenmitglieder, alles.

  1. Wie kann ich auf die privaten Methoden und die privaten Datenmitglieder zugreifen?
  2. Kann man über Reflection auf die lokale Variable zugreifen?
  3. Gibt es eine Möglichkeit, zu verhindern, dass jemand auf private Konstruktoren, Methoden und Datenmitglieder zugreift?
25
Eng.Fouad

1)Wie kann ich auf die privaten Methoden und die privaten Datenmitglieder zugreifen?

Sie können dies mit Hilfe der setAccessible(true)-Methode tun:

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)Kann über Reflektion auf eine lokale Variable zugegriffen werden?

Lokale Variablen können nicht außerhalb eines Blocks aufgerufen werden, in dem sie erstellt wurden (jemand könnte sagen, dass Sie einem Feld wie field = localVariable; eine solche Variable zuweisen können und später über Reflexion auf ein solches Feld zugreifen können.Wert, nicht die Variable).

3)Gibt es eine Möglichkeit, jemanden vom Zugriff auf private Konstruktoren, Methoden und Datenmitglieder abzuhalten?

Ich denke, für constructors oder methods könnten Sie stacktrace verwenden, um zu prüfen, ob es von Reflection..__ aufgerufen wurde.
Bei Feldern kann ich keine Lösung finden, um den Zugriff über Reflexion zu verhindern.

[WARNUNG: Dies wird von niemandem genehmigt. Ich habe es gerade geschrieben, inspiriert von Ihrer Frage.]

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);
    }
}

Ausgabe von Test main-Methode :

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
65
Pshemo
  1. Verwenden Sie die in der Antwort angegebene Methode, die Sie mit: setAccessible (true) verknüpft haben. Dies ist eine Methode der Oberklasse von Field, Constructor und Method.
  2. Nein.
  3. Nein, es sei denn, der Code wird in einer von Ihnen kontrollierten JVM ausgeführt, in der Sie einen Sicherheitsmanager installieren. Wenn Sie jedoch jemandem eine Jar-Datei geben und er die Klassen aus dieser Jar-Datei verwendet, kann er auf alles zugreifen.
9
JB Nizet

Für den Zugriffein privates Feld müssen Sie die Class.getDeclaredField(String name)- oder enter code here-Methode aufrufen. Überprüfen Sie diesen einfachen Code:

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

Für den Zugriff auf eine private Methode müssen Sie die Methode Class.getDeclaredMethod (Stringname, Class [] parameterTypes) oder die Methode Class.getDeclaredMethods () aufrufen.

Überprüfen Sie diesen einfachen Code:

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);

Weitere Informationen finden Sie unter http://tutorials.jenkov.com/Java-reflection/private-fields-and-methods.html

3
VdeX

Beispiel wie folgt:

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));
    }
}
1
 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]);
1
Om Deshmukh

Um Ihre dritte Frage zu beantworten:

  1. Gibt es eine Möglichkeit, zu verhindern, dass jemand auf private Konstruktoren, Methoden und Datenmitglieder zugreift?

Antworten:

Ja, Sie können den Zugriff einschränken (Sie können eine Ausnahme auslösen, wenn jemand versucht, auf Ihren privaten Konstruktor/Methode/Daten zuzugreifen).

Siehe das folgende Beispiel:

******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

Dieses Beispiel war für eine Singleton-Klasse (Einchecken im Konstruktor), Sie können diese Logik jedoch für die privaten Methoden implementieren, auf die Sie den Zugriff von anderen Klassen verhindern möchten.

In diesem Fall werden Sie auch eine statische Instanz deklarieren und deren Wert in der privaten Methode überprüfen und bei unerwünschten Werten einen Fehler ausgeben.

0
Onkar Nevgi