JAVA-反射
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
要想解剖一个类,必须先要获取到该类的字节码文件对象。而解剖使用的就是Class类中的方法.所以先要获取到每一个字节码文件对应的Class类型的对象。
阅读API的Class类得知,Class
没有公共构造方法。Class
对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的 defineClass
方法自动构造的
下面直接进行演示。
首先建立2个类
Person类
package cn.bruce.reflect; public class Person { public String name; public int age; private String address; public Person() { } public Person(String name, int age, String address) { this.name = name; this.age = age; this.address = address; } private Person(String name, int age) { this.name = name; this.age = age; } public void eat() { System.out.println(name + "想吃大餐!"); } private void eat(String name, int age) { System.out.println(name + "想吃大餐!" + "因为今年已经" + age + "岁了!"); } @Override public String toString() { return "Person [name=" + name + ", age=" + age + ", address=" + address+ "]"; } }
Student类
package cn.bruce.reflect; public class Student { public String name; public int age; private String address; public Student() { } public Student(String name, int age, String address) { this.name = name; this.age = age; this.address = address; } private Student(String name, int age) { this.name = name; this.age = age; } public void study() { System.out.println(name + "想要好好学习!"); } private void study(String name, int age) { System.out.println(name + "想要好好学习!" + "因为今年已经" + age + "岁了!"); } @Override public String toString() { return "Student [name=" + name + ", age=" + age + ", address=" + address+ "]"; } }
通过反射获取构造、字段、方法
package cn.bruce.reflect; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; public class Test { public static void main(String[] args) throws Exception { // Class c = Person.class;//这个是直接的 // 1,获取到Class对象 Class c = Class.forName("cn.bruce.reflect.Person");// 包名.类名 Constructor[] con = c.getConstructors();// 出来公有构造器 for (Constructor constructor : con) { System.out.println(constructor); } System.out.println("------------------------------------------"); Constructor[] con1 = c.getDeclaredConstructors();// 出来所有构造器 for (Constructor constructor : con1) { System.out.println(constructor); } System.out.println("------------------------------------------"); Field[] field = c.getFields();// 出来公有字段 for (Field f : field) { System.out.println(f); } System.out.println("------------------------------------------"); Field[] field1 = c.getDeclaredFields();// 出来所有字段 for (Field f : field1) { System.out.println(f); } System.out.println("------------------------------------------"); Method[] m1 = c.getDeclaredMethods();// 出来所有方法 for (Method m : m1) { System.out.println(m); } System.out.println("---------------------------"); Method m2 = c.getMethod("eat", null);// 出来公有指定方法 System.out.println(m2); System.out.println("---------------------------"); Method m3 = c.getDeclaredMethod("eat", String.class, int.class);// 出来私有指定方法 System.out.println(m3); } }
反射并使用各种方法、泛型擦除、通过配置文件进行反射
package cn.bruce.reflect; import java.io.FileReader; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Properties; public class Test1 { public static void main(String[] args) throws Exception { // 1,获取到Class对象 Class c = Class.forName("cn.bruce.reflect.Student"); // 2,获取指定的构造方法 // public Student()//空参 // Constructor con = c.getConstructor(null); // public Student(String name, int age, String address) Constructor con = c.getConstructor(String.class, int.class, String.class); // 3,通过构造方法类中Constructor的方法,创建对象 // Object obj = con.newInstance(null);//空参 Object obj = con.newInstance("小明", 22, "哈尔滨"); // 显示 System.out.println(obj); // 4,获取私有构造方法 Constructor con1 = c.getDeclaredConstructor(String.class, int.class); // 5,暴力反射 con1.setAccessible(true);// 取消 Java 语言访问检查 Object obj1 = con1.newInstance("小明", 22); System.out.println(obj1); // 6,获取指定的方法 Method m1 = c.getMethod("study", null);// 公有无参方法 Method m2 = c.getDeclaredMethod("study", String.class, int.class);// 私有 // 7,执行找到的方法 m1.invoke(obj); m2.setAccessible(true);// M2需要暴力反射 Object obj_m2 = m2.invoke(obj1, "小米", 99); // 以下测试泛型擦除 ArrayList<Integer> list = new ArrayList<Integer>(); list.add(999); // list.add("小米");出错 // 1、获取ArrayList的class对象 Class c_arr = Class.forName("java.util.ArrayList"); // 2、获取方法 Method m_arr = c_arr.getMethod("add", Object.class); // 3、调用方法 m_arr.invoke(list, "小米"); m_arr.invoke(list, "小毛"); System.out.println(list); // 以下演示配置文件实现反射功能 /* * 调用哪种方法不知道,类也不清楚,通过配置文件实现 运行类名与方法名,以键值对的形式,写在文本中 运行哪个类,读取配置文件即可 实现步骤 * 1、准备配置文件,键值对,IO流读取配置文件reader 2、文件中的键值对存储至集合Properties,集合保存键值对:类名及方法名 * 3、反射指定的class文件对象,获取方法 运行方法 */ // IO流读取 FileReader fr = new FileReader("config.properties"); // 创建集合对象 Properties p = new Properties(); // 调用集合方法,传递流对象 p.load(fr); fr.close(); // 通过键获取值 String classname = p.getProperty("classname"); String method = p.getProperty("method"); // 反射获取指定类的文件对象 Class c_pro = Class.forName(classname); // 可以传一下name // Constructor con_pro = c_pro.getConstructor(String.class, int.class, String.class); // Object obj_pro = con_pro.newInstance("笑笑", 33, "杭州");// 创建对象 Object obj_pro = c_pro.newInstance(); Method m_pro = c_pro.getMethod(method, null); m_pro.invoke(obj_pro, null); } }