一 反射简述
JAVA是一个静态语言,但是通过使用反射,我们可以在程序运行的时候获取一个类的所有的方法,属性,并且实现调用。
二 反射的使用
1.我们首先创建一个学生类
package markorg.top.demo; public class Student { private int age; public String name; private String school; public Student() { System.out.println("默认的构造方法"); } // 受保护的构造方法 protected Student(int age) { System.out.println("受保护的构造方法" + age); } // 私有构造方法 private Student(int age, String name) { System.out.println("受保护的构造方法" + "age: " + age + ",name: " + name); } // 完整的构造方法 public Student(int age, String name, String school) { super(); this.age = age; this.name = name; this.school = school; } public void print(String str) { System.out.println("hello student:" + str); } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getSchool() { return school; } public void setSchool(String school) { this.school = school; } }
2.接下来,首先通过反射获取Student 类的Class,然后调用reflect api获取到类的构造方法,实现类的初始化
package markorg.top.demo; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; public class ReflectTest { public static void main(String[] args) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException { Student stu = new Student(); // 第一种方式获取student对象 Class stuClass = stu.getClass();// 这种方法是在已经创建的情况下获取,实际中不需要 System.out.println(stuClass.getName()); // 第二种方式获取student对象 Class stuClass2 = Student.class; // 第三种方式获取student对象,常用的方法,需要注意的是Name需要包的完整路径名和类的名称 try { Class stuClass3 = Class.forName("markorg.top.demo.Student"); System.out.println(stuClass == stuClass2); } catch (ClassNotFoundException e) { e.printStackTrace(); } // 获取公有的构造方法 Constructor[] conArry = stuClass2.getConstructors(); System.out.println("公有构造"); for (Constructor con : conArry) { System.out.println(con); } // 获取所有的构造方法 Constructor[] conAll = stuClass2.getDeclaredConstructors(); System.out.println("所有构造"); for (Constructor cons : conAll) { System.out.println(cons); } Constructor ctr = stuClass2.getConstructor(null); // 调用构造 Object obj = ctr.newInstance(); // 带参数的构造方法 Constructor ctr2 = stuClass2.getDeclaredConstructor(int.class); // 调用构造 Object ob = ctr2.newInstance(20); Constructor pri = stuClass2.getDeclaredConstructor(int.class, String.class);// 注意,这里只能是类型.class,不能直接他的包装类型。 // 调用构造 // 设置可以访问 pri.setAccessible(true); Object ob3 = pri.newInstance(18, "tom"); } }
3.获取类的属性,方法,并且调用方法
package markorg.top.demo; import java.lang.reflect.Field; import java.lang.reflect.Method; public class GetFieldTest { public static void main(String[] args) { try { // 通过反射获取Class Class stuClass = Class.forName("markorg.top.demo.Student"); // 获取所有公有字段 Field[] field = stuClass.getFields(); for (Field fd : field) { System.out.println("公有字段:" + fd); } // 获取所有的字段 Field[] fields = stuClass.getDeclaredFields(); for (Field fds : fields) { System.out.println("全部字段:" + fds); } // 获取私有字段并调用 Field fie = stuClass.getDeclaredField("school"); fie.setAccessible(true); Object obb = stuClass.getConstructor().newInstance(); fie.set(obb, "苏州大学"); Student stt = (Student) obb; System.out.println("学校名字:" + stt.getSchool()); // 获取所有的方法 Method[] method = stuClass.getMethods(); for (Method met : method) { System.out.println("全部方法:" + met); } // 获取公有的某个方法,通过方法名来获取 Method pubmethod = stuClass.getMethod("print", String.class); System.out.println("私有方法:" + pubmethod); // pubmethod.setAccessible(true);如果是私有方法需要这个 pubmethod.invoke(obb, "jack");//通过invoke来进行调用 } catch (Exception e) { e.printStackTrace(); System.out.println("反射异常"); } } }
三 反射总结
乍看起来,我们好像没必要使用反射,因为正常情况下,通过实例化类,就可以直接使用他的方法,而且,反射会降低程序的性能,但是,有时候,我们是不知道这个类的属性的,比如一些ORM框架中,需要数据库中的表来和类进行映射,但是我们一开始是不知道将要映射的表是什么样的,是不能提前创建对应的类,这时候我们可以可以通过查询数据库,动态的生成表对应的class并且通过java自编译器动态加载到内存,达到动态生成对象进行映射的作用。相关操作,我将在下一个章节进行介绍。