一, 反射机制
在前面 Java 语法之注解自定义注解时我们也有提到反射, 要获取类方法和字段的注解信息, 必须通过 Java 的反射技术来获取 Annotation 对象. 那什么是反射呢? JAVA 反射机制是在运行状态中, 对于任意一个类, 都能够知道这个类的所有属性和方法; 对于任意一个对象, 都能够调用它的任意一个方法和属性; 这种动态获取的信息以及动态调用对象的方法的功能称为 java 语言的反射机制. 它有点类似照妖镜的作用, 不管是什么妖魔鬼怪 (类或对象) 都能看到它的真面目(获取类的属性方法, 调用对象的属性方法).
二, Class 理解
反射机制可以动态获取类信息以及调用对象方法, 那它是通过什么实现的呢? 这就要介绍下 Class 类了. 首先明确 Class 也是一个类, 只是它是一个描述类的类, 它也可以生成对象. 对于每个类而言, 在 JRE 中有且仅有一个不变的 Class 类型的对象, 而这个 Class 类型的对象只能由系统建立, 封装了当前对象所对应的类的信息, 有哪些属性, 方法, 构造器, 实现了哪些接口等等. 而且每个类的实例都会记得自己是由哪个 Class 实例所生成.
那要获取类信息或调用对象方法, 肯定首先要获取到该类或对象对应的 Class 类的实例. 一般获取 Class 对象有三种方式.
1. 通过类名获取 类名. class
2. 通过对象获取 对象. getClass()
3. 通过全类名获取 Class.forName(全类名)
这里我们可以使用用字符串来做验证. 输出结果都是 class java.lang.String.
- package Reflection;
- public class ReflectionTest {
- public static void main(String[] args) throws ClassNotFoundException {
- // 字符串的例子
- Class clazz = null;
- // 类名. class
- clazz = String.class;
- System.out.println(clazz);
- // 对象. getClass()
- clazz = "ReflectionTest".getClass();
- System.out.println(clazz);
- //Class.forName(全类名)
- clazz = Class.forName("java.lang.String");
- System.out.println(clazz);
- }
- }
- class java.lang.String
- class java.lang.String
- class java.lang.String
上面通过三种方式能获取到 Class 实例, 然后再了解一下 Class 类常用的方法
方法名 | 功能说明 |
forName(String name) | 返回指定类名 name 的 Class 对象 |
newInstance() | 调用缺省构造函数,返回该 < span style="font-family: Times New Roman" ztid="98" ow="26" oh="14">Class 对象的一个实例 |
newInstance(Object []args) | 调用当前格式构造函数,返回该 < span style="font-family: Times New Roman" ztid="107" ow="26" oh="14">Class 对象的一个实例 |
getName() | 返回此 < span style="font-family: Times New Roman" ztid="116" ow="26" oh="14">Class 对象所表示的实体(类、接口、数组类、基本类型或 void )名称 |
getSuperClass() | 返回当前 < span style="font-family: Times New Roman" ztid="127" ow="26" oh="14">Class 对象的父类的 Class 对象 |
getInterfaces() | 获取当前 < span style="font-family: Times New Roman" ztid="138" ow="26" oh="14">Class 对象的接口 |
getClassLoader() | 返回该类的类加载器 |
getSuperclass() | 返回表示此 < span style="font-family: Times New Roman" ztid="154" ow="26" oh="14">Class 所表示的实体的超类的 Class |
getFields() | 获取类中 < span style="font-family: Times New Roman" ztid="164" ow="30" oh="14">public 类型的属性 |
getField(String name) | 获取类特定的方法,name 参数指定了属性的名称 |
getDeclaredFields() | 获取类中所有的属性 < span style="font-family: Times New Roman" ztid="182" ow="34" oh="14">(public 、 protected 、 default 、 private), 但不包括继承的属性 |
getDeclaredField(String name) | 获取类特定的方法,name 参数指定了属性的名称 |
getConstructors() | 获取类中的公共方法 |
getConstructor(Class[] params) | 获取类的特定构造方法 < span style="font-family: Times New Roman" ztid="213" ow="38" oh="14">,params 参数指定构造方法的参数类型 |
getDeclaredConstructors() | 获取类中所有的构造方法 < span style="font-family: Times New Roman" ztid="222" ow="34" oh="14">(public 、 protected 、 default 、 private) |
getDeclaredConstructor(Class[] params) | 获取类的特定构造方法 < span style="font-family: Times New Roman" ztid="236" ow="38" oh="14">,params 参数指定构造方法的参数类型 |
getMethods() | 获得类的 < span style="font-family: Times New Roman" ztid="245" ow="30" oh="14">public 类型的方法 |
getMethod(String name, Class[] params) | 获得类的特定方法 < span style="font-family: Times New Roman" ztid="254" ow="29" oh="14">,name 参数指定方法的名字 ,params 参数指定方法的参数类型 |
getDeclaredMethods() | 获取类中所有的方法 < span style="font-family: Times New Roman" ztid="265" ow="34" oh="14">(public 、 protected 、 default 、 private) |
getDeclaredMethod(String name, Class[] params) | 获得类的特定方法 < span style="font-family: Times New Roman" ztid="279" ow="29" oh="14">,name 参数指定方法的名字 ,params 参数指定方法的参数类型 |
三, 反射的使用
这里要着重介绍下上面 API 的使用, 因为在后面要学习的 Spring 中 IOC 的原理就是反射加工厂模式. 学好反射 API 有助于理解 Spring 框架内部实现. 为了演示 Class 方法的使用, 在注解 demo 的基础上对 Person,Student 类进行了修改.
Person 类:
- package Reflection;
- @CustomDescription(description="基类")
- @CustomDescription(description="人")
- public class Person {
- private String Name;
- public String getName() {
- return Name;
- }
- public void setName(String name) {
- Name = name;
- }
- public String PersonPublicMethod(String str)
- {
- return str;
- }
- public Person(String name) {
- Name = name;
- }
- public String PersonPrivateMethod(String str)
- {
- return str;
- }
- public Person() {
- super();
- }
- }
- View Code
Student 类:
- package Reflection;
- @CustomDescription(description="学生")
- @CustomDescription(description="人")
- public class Student extends Person {
- public String StudentId;
- public String getStudentId() {
- return StudentId;
- }
- public void setStudentId(String studentId) {
- StudentId = studentId;
- }
- public String StudentPublicMethod(String str)
- {
- return str;
- }
- private String StudentPrivateMethod(String str)
- {
- return str;
- }
- public Student(String name, String studentId) {
- super(name);
- StudentId = studentId;
- }
- public Student() {
- }
- }
- View Code
一, 描述方法 Method
描述方法的主要是 4 个获取方法 getMethods,getMethod,getDeclaredMethods,getDeclaredMethod 和 1 个调用方法 invoke.
getMethods: 获取 clazz 对应类中的所有方法, 不能获取 private 方法, 且获取从父类继承来的所有方法包括私有父类的私有方法
getMethod: 获取 clazz 对应类中指定方法名和参数类型的方法, 不能获取 private 方法, 且获取从父类继承来的所有方法包括私有父类的私有方法, 因为存在同方法名不同参数这种情况, 所以只有同时指定方法名和参数类型才能唯一确定一个方法.
getDeclaredMethods: 获取所有方法, 包括私有方法, 所有声明的方法, 都可以获取到, 且只获取当前类的方法.
getDeclaredMethod: 获取 clazz 对应类中指定方法名和参数类型的方法, 包括私有方法, 所有声明的方法, 都可以获取到, 且只获取当前类的方法.
Invoke: 执行方法, 第一个参数表示执行哪个对象的方法, 剩下的参数是执行方法时需要传入的参数, 私有方法的执行, 必须在调用 invoke 之前加上一句 method.setAccessible(true);
- public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
- Class clazz = Class.forName("Reflection.Student");
- Method method=null;
- Method[] methods=null;
- methods = clazz.getMethods();
- for(Method mth:methods){
- System.out.print(mth.getName()+" ");
- }
- System.out.println();
- method = clazz.getMethod("StudentPublicMethod",String.class);
- System.out.print(method.getName()+" ");
- System.out.println();
- methods = clazz.getDeclaredMethods();
- for(Method mth:methods){
- System.out.print(mth.getName()+" ");
- }
- System.out.println();
- method = clazz.getDeclaredMethod("StudentPrivateMethod",String.class);
- System.out.print(method.getName()+" ");
- System.out.println();
- Object obje = clazz.newInstance();
- method.setAccessible(true);
- String result=(String) method.invoke(obje,"inputParams");
- System.out.println(result);
- }
输出结果:
- StudentPublicMethod setStudentId getStudentId getName setName PersonPrivateMethod PersonPublicMethod wait wait wait equals toString hashCode getClass notify notifyAll
- StudentPublicMethod
- StudentPrivateMethod StudentPublicMethod setStudentId getStudentId
- StudentPrivateMethod
- inputParams
二, 描述字段 Filed
描述字段 Filed 方法的使用和描述方法 Method 中方法的使用有点类似, 也是 4 个获取字段的方法: getFields,getField,getDeclaredFields,getDeclaredField.
getFields: 获得某个类的所有的公共 (public) 的字段, 包括父类中的字段.
getField: 获取某个类 public 成员变量中指定变量名的字段, 包括基类.
getDeclaredFields: 获得某个类的所有声明的字段, 即包括 public,private 和 proteced, 但是不包括父类的申明字段.
getDeclaredField: 获取某个类的所有成员变量指定变量名的字段, 不包括基类.
1. 字段获取
- Class clazz = Class.forName("Reflection.Student");
- System.out.println("---------getDeclaredFields---------");
- Field[] fields = clazz.getDeclaredFields();
- for(Field field: fields){
- System.out.print(field.getName()+" ");
- }
- System.out.println();
- System.out.println("---------getFields---------");
- fields = clazz.getFields();
- for(Field field: fields){
- System.out.print(field.getName()+" ");
- }
- System.out.println();
- System.out.println("---------getDeclaredField---------");
- Field field = clazz.getDeclaredField("StudentId");
- field.setAccessible(true);
- System.out.println(field.getName());
- System.out.println("---------getField--------");
- field = clazz.getField("StudentId");
- System.out.println(field.getName());
- ---------getDeclaredFields---------
- StudentId
- ---------getFields---------
- StudentId
- ---------getDeclaredField---------
- StudentId
- ---------getField--------
- StudentId
2. 字段的使用
- Class clazz = Class.forName("Reflection.Person");
- Person person = new Person("CYW");
- // 获取私有字段的值
- Field field = clazz.getDeclaredField("Name");
- // 由于是私有字段, 需要使用 setAccessible(true)
- field.setAccessible(true);
- Object val = field.get(person);
- System.out.println(val);
- // 改变私有字段的值
- field.set(person, "ivan");
- System.out.println(person.getName());
计划在未来 6 个月内写一本 Spring 入门的书, 本篇和 Java 语法注解篇都是书的一部分, 博友有什么建议或意见可以留言, 我也好在后面的章节进行改进. 未完, 待续!
来源: https://www.cnblogs.com/5ishare/p/9452264.html