我像这样动态地获取一个类:
Class<?> clazz = Class.forName("com.android.systemui.quicksettings.QuickSettingsTile");
我想创建另一个名为DummyTile
的类,它扩展了我之前的课程。它看起来像这样:
public class DummyTile extends QuickSettingsTile {
public DummyTile(Context context, QuickSettingsController qsc) {
super(context, qsc);
}
public void updateTile() {
System.out.println("Hello");
}
@Override
public void updateResources() {
updateTile();
super.updateResources();
}
}
...但我不确定如何使用反射来做到这一点。 This is the class that I'm trying to extend.我也不确定如何使用构造函数覆盖方法并初始化对象。我使用反射处理非常简单的事情,但从未处理过动态扩展另一个类。
如果有人能用一些片段指出我正确的方向,我相信我能够从那里处理它。
答案 0 :(得分:3)
你不能用反射做到这一点。您可以使用interface
动态创建java.lang.reflect.Proxy
实现,但就是这样。
如果您想要更多,则必须使用第三方库。但是这些库通常在较低级别上工作,例如字节码并需要一些经验。它们不能在受限制的环境中使用。
答案 1 :(得分:1)
你无法使用反射扩展一个类,但你可以封装它 这当然是一个主要的安全风险,您应该认真思考是否要允许这样做。
这样的事情应该可以解决问题。
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.lang.ClassNotFoundException;
import java.lang.InstantiationException;
import java.lang.IllegalAccessException;
import java.lang.reflect.InvocationTargetException;
import java.lang.NoSuchMethodException;
public class Tester {
private static String CLASS_NAME = "VictimClass";
private static Class victimClass = null;
private static Object victimClassObj = null;
public static void main(String[] args) {
victimClass = loadClass(victimClass, CLASS_NAME);
printClassStructure();
attack();
}
private static Class loadClass(Class clazz, String className) {
Thread thread = Thread.currentThread();
ClassLoader classLoader =
thread.getContextClassLoader();
try {
clazz = Class.forName(className, true, classLoader);
}
catch (ClassNotFoundException e) {
System.err.println("Error: could not find class: "
+ CLASS_NAME);
}
return clazz;
}
private static void printClassStructure() {
Constructor[] constructors =
victimClass.getDeclaredConstructors();
for (Constructor c : constructors) {
int modifier = c.getModifiers();
System.out.println("Declared constructor name: "
+ c.getName() + "ntis accessible: "
+ c.isAccessible() + "ntis private: "
+ Modifier.isPrivate(modifier) + "n");
}
Method[] methods = victimClass.getDeclaredMethods();
for (Method m : methods) {
int modifier = m.getModifiers();
System.out.println("Declared method name: " + m.getName()
+ "ntis accessible: "
+ m.isAccessible()
+ "ntis private: "
+ Modifier.isPrivate(modifier)
+ "ntis static: "
+ Modifier.isStatic(modifier) + "n");
}
Field[] fields = victimClass.getDeclaredFields();
for (Field f : fields) {
int modifier = f.getModifiers();
System.out.println("Declared field name: " + f.getName()
+ "ntis accessible: "
+ f.isAccessible()
+ "ntis private: "
+ Modifier.isPrivate(modifier)
+ "ntis static: "
+ Modifier.isStatic(modifier)
+ "ntis final: "
+ Modifier.isFinal(modifier) + "n");
}
}
private static void attack() {
Field[] fields = victimClass.getDeclaredFields();
Method[] methods = victimClass.getDeclaredMethods();
Constructor[] constructors = victimClass.getDeclaredConstructors();
//make constructor accessible
constructors[0].setAccessible(true);
System.err.println("Initiating reflection attack:");
try {
//create new object by invoking private constructor
victimClassObj = constructors[0].newInstance(new Object[] {});
//make static method accessible and get its value
//please note: when invoking static method,
//object represented by this Method is null
methods[2].setAccessible(true);
Object o = methods[2].invoke(null, new Object[] {});
System.out.println("Got user ID from private static accessor: "
+ o.toString());
//make method accessible and get its value
methods[0].setAccessible(true);
o = methods[0].invoke(victimClassObj, new Object[] {});
System.out.println("Got original password from private accessor: "
+ o.toString());
//make method accessible and set to it new value
methods[1].setAccessible(true);
System.out.println("Injecting new password using private mutator");
methods[1].invoke(victimClassObj, new Object[] {"injected_password"});
//get method’s its new value
o = methods[0].invoke(victimClassObj, new Object[] {});
System.out.println("Got injected password from private accessor: "
+ o.toString());
//make field accessible and get its value
fields[2].setAccessible(true);
o = fields[2].get(victimClassObj);
System.out.println("Got private field: " + o);
//make field accessible and set to it new value
System.out.println("Injecting value to a private field:");
fields[2].set(victimClassObj, "new_default_value");
//get field’s its new value
o = fields[2].get(victimClassObj);
System.out.println("Got updated private field: " + o);
//make field accessible and get its value
fields[1].setAccessible(true);
o = fields[1].get(victimClassObj);
System.out.println("Got private static field: " + o);
//make field accessible and set to it new value
System.out.println("Injecting value to a private static final field:");
fields[1].set(null, new Integer(2));
//get field’s its new value
o = fields[1].get(victimClassObj);
System.out.println("Got updated private static final field: " + o);
}
catch (InstantiationException e) {
System.err.println("Error: could not instantiate: " + e);
}
catch (IllegalAccessException e) {
System.err.println("Error: could not access: " + e);
}
catch (InvocationTargetException e) {
System.err.println("Error: could not invoke the target: " + e);
}
}
}
答案 2 :(得分:0)
您可以使用Duckapter向Java添加duck typing。
DummyTile tile = ...;
QuickSettingsTile settingsTile = Duck.type(tile, QuickSettingsTile.class);