0305 反射
1、通过反射获取构造方法
构造方法使用类Constructor表示
返回一个构造方法
public Constructor<T> getConstructor(Class<?>... parameterTypes) 获取public修饰, 指定参数类型所对应的构造方法
public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) 获取指定参数类型所对应的构造方法(包含私有的)
通过字节码文件对象调用上述两个方法就能获取到构造方法对象,获取构造方法对象之后需要调用Constructor中的newInstance方法去通过构造方法创建对象
代码展示
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { //获取Person的字节码文件对象 Class c=Class.forName("com.oracle.demo02.Person"); //获取构造方法对象 Constructor con=c.getDeclaredConstructor(String.class); //取消java检查 con.setAccessible(true); //创建对象 //暴力反射(不推荐使用 破坏了封装性) Person p=(Person)con.newInstance("小红"); p.eat(); }
上述中Person中获取的是一个私有的构造方法,私有构造方法不允许创建对象,那只能调用Constructor的父类中的setAccessible方法去开启 取消java检查,那就java就不会检查是不是私有的构造创建对象
2、通过反射获取成员变量
类中的成员变量使用类Field表示
返回一个成员变量
public Field getField(String name) 获取指定的 public修饰的变量
public Field getDeclaredField(String name) 获取指定的任意变量
代码展示
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, SecurityException, InstantiationException, IllegalAccessException { //获取字节码文件兑现 Class c=Class.forName("com.oracle.demo02.Person"); //获取成员变量对象 Field f=c.getField("name"); //快速创建对象 Object obj=c.newInstance(); //给成员变量赋值 f.set(obj, "你好"); //取值 System.out.println(f.get(obj)); }
上述代码中 我们获得了成员变量,那我们想给这个成员变量那就必须有一个对象,所以这里调用了Class类中的newInstance方法能够快速创建一个对象,那我们获取到成员变量的对象,那我们要给成员变量赋值,那么要调用Filed类中的 set方法去赋值,public void set(Object obj, Object value) 传一个指定object对象 传一个value值,取值是通过public Object get(Object obj)方法
3、通过反射获取成员方法并使用
类中的成员方法使用类Method表示
返回获取一个方法
public Method getMethod(String name, Class<?>... parameterTypes)获取public 修饰的方法
public Method getDeclaredMethod(String name, Class<?>... parameterTypes)获取任意的方法,包含私有的
代码展示
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException { //获取字节码文件对象 Class c=Class.forName("com.oracle.demo02.Person"); //获取成员方法对象 Method m=c.getMethod("eat", String.class,int.class); //快速创建对象 Object obj=c.newInstance(); //执行方法 m.invoke(obj, "小红马",18); }
在上述方法中同样运用到了快速创建对象的方法,获取到成员方法那么想使用的话需要调用Method类中public Object invoke(Object obj, Object... args)方法
反射练习之泛型擦除
例如我们创建一个ArrayList<Integer> arr=new ArrayList<Integer>();集合 我们发现有泛型 arr.add(123); 可以正常运行,那么arr.add("abc");是不能运行的因为 泛型是integer 不能存String类型的数据,在java中有两种东西进不到内存中去 一个是注释,一个就是泛型,那么我们可以通过反射操作他的字节码文件 去将不属于这个泛型类型的数据存入到有泛型规范的集合中去
代码展示
public static void main(String[] args) throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException { ArrayList<Integer> arr=new ArrayList<Integer>(); arr.add(123); //arr.add("abc"); //获取字节码文件对象 Class c=arr.getClass(); //获取成员方法对象 Method m=c.getMethod("add", Object.class); //执行方法 m.invoke(arr, "abc"); //遍历 for(Object obj:arr){ System.out.println(obj); } }
反射练习之配置文件
首先创建两个实体类
public class Student { public void study(){ System.out.println("学生学习"); } }
public class Worker { public void work(){ System.out.println("工人工作"); } }
创建一个properties类文件
className=com.oracle.demo04.Worker method=work
创建一个测试类
public class Demo01 { public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException,
IllegalAccessException, IllegalArgumentException, InvocationTargetException { //通用的方式 反射配置文件 //明确数据源 FileReader fr=new FileReader("src/com/oracle/demo04/pro.properties"); //创建集合 Properties pro=new Properties(); //将文件中的键值对度到集合中 pro.load(fr); //获取类名 String className=pro.getProperty("className"); //获取方法名 String methodName=pro.getProperty("method"); //获取字节码文件对象 Class c=Class.forName(className); //获取成员方法对象 Method m=c.getMethod(methodName); //快速创建对象 Object obj=c.newInstance(); //执行 m.invoke(obj); } }