共计 4062 个字符,预计需要花费 11 分钟才能阅读完成。
一、反射 Reflection 和 元类 Class
Class 元类是对一般类的形象,是类的类。Class 蕴含了一个类的所有属性,包含类名、包名、父类、实现的接口、所有办法、属性等。拿到一个类的 Class 元类,就拿到了这个类所有信息,就能够通过这些信息动静做一些解决。
通过一个类的 Class 实例获取类信息的办法就称为反射(Reflection)。
获取类的 Class 元类对象
办法一:间接通过动态变量 class
获取:
Class cls = String.class;
办法二:如果咱们有一个实例变量,能够通过该实例变量提供的 getClass()
办法获取:
String s = "Hello";
Class cls = s.getClass();
办法三:如果晓得一个类的残缺类名,能够通过静态方法 Class.forName()
获取:
Class cls = Class.forName("java.lang.String");
操作 Field 和 Method
拿到了类的 Class 元类实例就是调用如下办法获取类的属性和办法等。
Field getField(name):依据字段名获取某个 public 的 field(包含父类)Field getDeclaredField(name):依据字段名获取以后类的某个 field(不包含父类)Field[] getFields():获取所有 public 的 field(包含父类)Field[] getDeclaredFields():获取以后类的所有 field(不包含父类)Method getMethod(name, Class...):获取某个 public 的 Method(包含父类)Method getDeclaredMethod(name, Class...):获取以后类的某个 Method(不包含父类)Method[] getMethods():获取所有 public 的 Method(包含父类)Method[] getDeclaredMethods():获取以后类的所有 Method(不包含父类)
操作类的属性,实现动静扭转类
失去 Field 对象或 Method 对象后,get set 值时都须要指定一个该类的实例,也就是 get set 针对哪个对象操作。
Demo d = new Demo();
d.name = "testname";
clazz.getDeclaredField("name").get(d);// 参数 d 就是指定在 d 实例上做 get name 操作
clazz.getMethod("hello").invoke(d); // 参数 d 示意在 d 实例上调用 hello 对象
通过 Class 生成类实例
形式一:Class 对象的 newInstance 办法
Person p = Person.class.newInstance();
调用 Class.newInstance()的局限是,它只能调用该类的 public 无参数构造方法。如果构造方法带有参数,或者不是 public,就无奈间接通过 Class.newInstance()来调用。
形式二:反射获取 Constructor 对象
// 获取构造方法,getConstructor 办法参数传入类型要与构造方法须要的参数类型相符合。Constructor<Demo> constructor = clazz.getConstructor(String.class, Integer.class);
// 通过 constructor 生成实例
Demo aaa = constructor.newInstance("aaa", 123);
// clazz 在 aaa 对象上获取 name 属性
clazz.getDeclaredField("name").get(aaa);
二、注解的应用
注解分为定义注解,应用注解,解析注解。
注解有点像 Interface,但区别是注解中定义的办法,在应用时是通过属性赋值来应用的。
public @interface MyAnnotation {
// getValue 定义相似 Interface 的办法
// 区别是在注解应用时,不是调用 getValue,而是给 getValue 赋值,未赋值则默认应用 default 值。String getValue() default "no desc";}
public class Demo {
// 给 getValue 赋值一个字符串
@MyAnnotation(getValue = "annotation on field")
public String name;
}
元注解
元注解就是给注解用的注解,罕用的是 @Target 和 @Retention
Target 申明本注解可用在什么地位,如 ElementType.TYPE, ElementType.FIELD, ElementType.METHOD
Retention 表明本注解保留到什么时候,分为 RetentionPolicy.RUNTIME RetentionPolicy.SOURCE RetentionPolicy.CLASS
如果须要再运行时动静解决的注解,没有申明为 RUNTIME,则再运行时中就反射不到注解了。
解析注解
解析注解就是通过反射 Reflection 获取到一个类的全副信息,包含类下面的注解,再依据注解和其中的属性值进一步做响应的解决。
注解残缺三步
定义注解:
package com.sqkb.userasset;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @Author songzai
* @Date 2021/11/12 15:10
*/
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
// value 属性在应用时能够省略 key 名,即不须要写 value = xxx
int value() default 123;
String getValue() default "no desc";
String aaaa() default "default aaa";}
Demo 实体类,应用注解
package com.sqkb.userasset;
/**
* @Author songzai
* @Date 2021/11/12 15:10
*/
// 不写参数名,默认复制给 value()
@MyAnnotation(444)
public class Demo {public Demo(String name, Integer age) {
this.name = name;
this.age = age;
}
@MyAnnotation(getValue = "annotation on field")
public String name;
public Integer age;
@MyAnnotation(getValue = "annotation on method")
public void hello() {System.out.println("hello method");
}
public static void staticMethod() {System.out.println("static method");
}
@MyAnnotation()
public void defaultMethod() {}
}
解析注解:
package com.sqkb.userasset;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
/**
* @Author songzai
* @Date 2021/11/12 15:17
*/
public class AnnotationTest {public static void main(String[] args) throws Exception {
Class<Demo> clazz = Demo.class;
MyAnnotation annotationOnClass = clazz.getAnnotation(MyAnnotation.class);
System.out.println(annotationOnClass.getValue());
System.out.println(annotationOnClass.aaaa());
Field name = clazz.getField("name");
MyAnnotation annotation = name.getAnnotation(MyAnnotation.class);
System.out.println(annotation.getValue());
System.out.println(annotation.aaaa());
Method hello = clazz.getMethod("hello");
MyAnnotation helloAnnotation = hello.getAnnotation(MyAnnotation.class);
System.out.println(helloAnnotation.getValue());
System.out.println(helloAnnotation.aaaa());
Method defaultMethod = clazz.getMethod("defaultMethod");
MyAnnotation defaultMethodAnnotation = defaultMethod.getAnnotation(MyAnnotation.class);
System.out.println(defaultMethodAnnotation.getValue());
}
}
本文由 mdnice 多平台公布