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?
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?
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.
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
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
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));
}
}
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]);
Um Ihre dritte Frage zu beantworten:
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.