以前的学习笔记,自用的反射笔记,比较杂乱无章,甚在内容全
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
基础版:
public class reflection1 { public static void main(String[] args) throws Exception { Class.forName("xxx"); } } class xxx{ public xxx(){ System.out.println("xxx"); } static { System.out.println("xxx1"); } { System.out.println("xxx2"); } }
forName获取一个类,当运行这段代码,会动态调用static静态代码块:
获取函数方法:
测试代码块:
public class reflection1 { public static void main(String[] args) throws Exception { Class clazz=Class.forName("xxx"); //实例化类,然后调用方法 clazz.getMethod("hello").invoke(clazz.newInstance()); } } class xxx{ public xxx(){ System.out.println("xxx"); } public void hello(){ System.out.println("hello"); } static { System.out.println("xxx1"); } { System.out.println("xxx2"); } }
执行函数invoke后,会调用类的构造方法,因为初始化优先级,{}会比构造方法先调用,而方法是最后调用
所以最后的输出结果是:
获取构造方法:
import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; public class Reflection { public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, ClassNotFoundException { Class<?> clazz = Class.forName("zzz"); Constructor<?> constructor = clazz.getDeclaredConstructor(); constructor.setAccessible(true); constructor.newInstance(); } } class zzz{ private zzz(){ System.out.println("this is zzz"); } private zzz(String name){ System.out.println("this is "+name); } private zzz(int age,String name){ System.out.println("this is "+age+":"+name); } }
如果我们想获取有参构造方法怎么做?
一样使用getDeclaredConstructor();
import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; public class Reflection { public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, ClassNotFoundException { Class<?> clazz = Class.forName("zzz"); Constructor<?> constructor = clazz.getDeclaredConstructor(String.class); constructor.setAccessible(true); constructor.newInstance("test"); } } class zzz{ private zzz(){ System.out.println("this is zzz"); } private zzz(String name){ System.out.println("this is "+name); } private zzz(int age,String name){ System.out.println("this is "+age+":"+name); } }
除了使用getDeclaredConstructor
还可以使用getDeclaredConstructors
import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; public class Reflection { public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, ClassNotFoundException { Class<?> clazz = Class.forName("zzz"); // Constructor<?> constructor = clazz.getDeclaredConstructor(String.class); // constructor.setAccessible(true); // constructor.newInstance("test"); Constructor<?>[] constructors = clazz.getDeclaredConstructors(); Constructor constructor = constructors[0]; constructor.setAccessible(true); // 输出内容 System.out.println(constructor); constructor.newInstance(); } } class zzz{ private zzz(){ System.out.println("this is zzz"); } private zzz(String name){ System.out.println("this is "+name); } private zzz(int age,String name){ System.out.println("this is "+age+":"+name); } }
如果想获取有参构造方法:
getDeclaredConstructors
带s说明获取所有构造方法,[0]代表第一位:
有参构造方法在第1位置,那么修改demo:
import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; public class Reflection { public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, ClassNotFoundException { Class<?> clazz = Class.forName("zzz"); // Constructor<?> constructor = clazz.getDeclaredConstructor(String.class); // constructor.setAccessible(true); // constructor.newInstance("test"); Constructor<?>[] constructors = clazz.getDeclaredConstructors(); Constructor constructor = constructors[1]; constructor.setAccessible(true); // 输出内容 System.out.println(constructor); constructor.newInstance("test"); } } class zzz{ private zzz(){ System.out.println("this is zzz"); } private zzz(String name){ System.out.println("this is "+name); } private zzz(int age,String name){ System.out.println("this is "+age+":"+name); } }
获取私有构造方法,私有字段,私有方法:
import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; public class reflection2 { public static <Feild> void main(String[] args) throws Exception { //获取类 Class clazz=Class.forName("test"); //获取私有方法 Constructor c = clazz.getDeclaredConstructor(); c.setAccessible(true); //获取私有方法 Method method = clazz.getDeclaredMethod("test", String.class, String.class); method.setAccessible(true); method.invoke(c.newInstance(),"aaa","bbb"); //获取私有字段 Field field = clazz.getDeclaredField("age"); field.setAccessible(true); System.out.println(field.get(c.newInstance())); } } class test{ private test(){ System.out.println("test"); } private int age=222; private void test(String name1,String name2){ System.out.println(name1+":"+name2); } }
即使构造方法,字段,方法是public,也是受用的。
反射调用java.lang.Runtime方法:
Runtime类的构造方法是私有的,所以我们代码如下:
public class reflection3 { public static void main(String[] args) throws Exception { //Class clazz=Class.forName("java.lang.Runtime"); // clazz.getMethod("exec", String.class).invoke(clazz.getMethod("getRuntime").invoke(clazz),"open /Users/maniac/aaaa.txt"); Class clazz = Class.forName("java.lang.Runtime"); //获取构造方法,包含public,private,protect Constructor c = clazz.getDeclaredConstructor(); c.setAccessible(true); clazz.getMethod("exec", String.class).invoke(c.newInstance(),"open /Users/maniac/aaaa.txt"); } }
启动成功:
java.lang.Runtime反射调用2:
因为java.lang.Runtime执行命令是:java.lang.Runtime.getRuntime().exec()
所以直接调用:
getRuntime()和exec()方法都是公开方法,那么可以这样:
public class reflection4 { public static void main(String[] args) throws Exception { // java.lang.Runtime.getRuntime().exec(); Class clazz=Class.forName("java.lang.Runtime"); clazz.getMethod("exec", String.class).invoke(clazz.getMethod("getRuntime").invoke(clazz),"open /Users/maniac/aaaa.txt"); } }
优先获取最后的方法,然后往前移动。
流程:java.lang.Runtime.getRuntime().exec(command)->exec()->exec()->getRuntime()->java.lang.Runtime->command
修改私有属性和方法里面的属性:
import jdk.nashorn.internal.objects.NativeDebug; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class Reflection { private static java.lang.Object Object; public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, ClassNotFoundException, NoSuchFieldException { Class<?> clazz = Class.forName("zzz"); Class.forName("java.lang.Runtime"); // Constructor<?> constructor = clazz.getDeclaredConstructor(String.class); // constructor.setAccessible(true); // constructor.newInstance("test"); Constructor<?>[] constructors = clazz.getDeclaredConstructors(); Constructor constructor = constructors[1]; constructor.setAccessible(true); // 输出内容 System.out.println(constructor); // constructor.newInstance("test"); // Method xxx = clazz.getMethod("xxx"); // System.out.println(xxx); //实例化 Object o=constructor.newInstance("test"); Field field = clazz.getDeclaredField("name"); field.setAccessible(true); field.set(o,"hello"); Object xx=field.get(o); //修改变量 System.out.println(xx); // System.out.println(field.get(constructor.newInstance("test"))); // clazz.getMethod("xxx").invoke(constructor.newInstance("test")); // clazz.getDeclaredField("name").setAccessible(true); Method method = clazz.getDeclaredMethod("xxx"); method.setAccessible(true); //修改方法 method.invoke(o); } } class zzz{ private zzz(){ System.out.println("this is zzz"); } private zzz(String name){ System.out.println("this is "+name); } private zzz(int age,String name){ System.out.println("this is "+age+":"+name); } public int age=123; private String name="jack"; public void xxx(){ System.out.println(name); } }
总结:getMethod:是获取方法
invoke是执行方法,里面放的是实例化类
newInstance()是对类的实例化
获取字段返回类型:
Field i = demo.getDeclaredField("i"); i.setAccessible(true); int modifiers = i.getModifiers();
返回类型有这些:
PUBLIC: 1 PRIVATE: 2 PROTECTED: 4 STATIC: 8 FINAL: 16 SYNCHRONIZED: 32 VOLATILE: 64 TRANSIENT: 128 NATIVE: 256 INTERFACE: 512 ABSTRACT: 1024 STRICT: 2048
去final修饰符修改字段:
测试demo:
反射修改number为13:
Class<?> aClass = Class.forName("com.reflection.demo"); Field number = aClass.getDeclaredField("number"); number.setAccessible(true); Field modifiers = number.getClass().getDeclaredField("modifiers"); modifiers.setAccessible(true); modifiers.setInt(number,number.getModifiers()&~Modifier.FINAL); number.setInt(null,13); System.out.println(number.get(null));
反射调用内部类:
//反射调用内部类 @Test public void test4() throws ClassNotFoundException, IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException, NoSuchFieldException { Class c = Class.forName("com.test.BasicTest.refInnerClass"); Constructor declaredConstructor1 = c.getDeclaredConstructor(); declaredConstructor1.setAccessible(true); //通过方法名获取方法 Method method = c.getDeclaredMethod("print"); //调用外部类方法 method.invoke(c.newInstance()); //内部类需要使用$分隔 Class c2 = Class.forName("com.test.BasicTest.refInnerClass$InnerClass"); Method method2 = c2.getDeclaredMethod("print2"); Constructor declaredConstructor = c2.getDeclaredConstructor(c); declaredConstructor.setAccessible(true); method2.setAccessible(true); //获取方法 method2.invoke(declaredConstructor.newInstance(c.newInstance())); //修改isTrue为true Field isTrue = c2.getDeclaredField("isTrue"); isTrue.setAccessible(true); Field modifiers = isTrue.getClass().getDeclaredField("modifiers"); modifiers.setAccessible(true); //去除final修饰符 modifiers.setInt(isTrue,isTrue.getModifiers()&~Modifier.FINAL); isTrue.setBoolean(null,true); System.out.println(isTrue.get(null)); //调用私有方法 Method test2 = c2.getDeclaredMethod("test2"); test2.setAccessible(true); test2.invoke(declaredConstructor.newInstance(declaredConstructor1.newInstance())); }
for循环反射调用内部类方法和字段:
//反射内部类批量调用方法,字段名字 @Test public void test5() throws ClassNotFoundException { com.test.BasicTest.refInnerClass refInnerClass = new refInnerClass(); Class<?> aClass = Class.forName("com.test.BasicTest.refInnerClass"); //获取所有类 Class<?>[] declaredClasses = refInnerClass.class.getDeclaredClasses(); Arrays.stream(declaredClasses).forEach(clazz -> { Arrays.stream(clazz.getDeclaredMethods()).forEach(method -> { Arrays.stream(clazz.getDeclaredFields()).forEach(field -> { field.setAccessible(true); method.setAccessible(true); try { // 获取内部类的构造方法,内部类的构造只能通过外部类来获取 Constructor<?> declaredConstructor = clazz.getDeclaredConstructor(aClass); declaredConstructor.setAccessible(true); // 由外部类对象来反射获取内部类的对象 Object o = declaredConstructor.newInstance(aClass.newInstance()); method.invoke(o); Field modifiers = field.getClass().getDeclaredField("modifiers"); modifiers.setAccessible(true); modifiers.setInt(field, field.getModifiers() & ~Modifier.FINAL); Object o1 = field.get(o); System.out.println(o1); } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException | InstantiationException | NoSuchFieldException e) { e.printStackTrace(); } }); }); }); }
for循环反射调用类的方法和字段:
@Test //反射批量调用方法,名字 public void test6() throws ClassNotFoundException { Class<?> aClass = Class.forName("com.test.BasicTest.reflectionDemo"); Arrays.stream(aClass.getDeclaredMethods()).forEach(method -> { Arrays.stream(aClass.getDeclaredFields()).forEach(field -> { method.setAccessible(true); field.setAccessible(true); try { Constructor<?> declaredConstructor = aClass.getDeclaredConstructor();; declaredConstructor.setAccessible(true); method.invoke(declaredConstructor.newInstance()); Object o = field.get(null); System.out.println(o); } catch (IllegalAccessException | InvocationTargetException |NoSuchMethodException|InstantiationException e) { e.printStackTrace(); } }); }); }
无关紧要的一些反射加载类缩写:
一个数组 [Ljava.lang.String;
二维数组 [[Ljava.lang.String;
三维数组 [[[Ljava.lang.String;
float[].class=[F double[].class=[D long[].class=[J int[].class=[I short[].class=[S char[].class=[C byte[].class=[B Boolean[].class=[Ljava.lang.Boolean; Integer[].class=[Ljava.lang.Integer; Object[].class=[Ljava.lang.Object;
一个[为一维数组,2个[为2维,依次递增
神坑:java反射数组参数,Runtime.exec 传递new String报错问题:
反射数组参数参考:https://www.jianshu.com/p/b8873c1ad0ef
解决:加个(Object),转换为Object
后续如果还有反射知识点再补充