• 反射
  • 获取Class对象的三种方式
  • 反射创建类对象
  • 反射获取field
  • 反射获取method
  • 反射获取constructor
  • 反射获取泛型
  • 反射获取注解
  • 注解
  • jdk的3个内置注解
  • 5个元注解:@Retention,@Target ...
  • 注解的属性
  • 注解的本质:Annotation接口的子接口

1. 反射概念

  • 反射:在程序运行期,对于任意一个类,都能动态获取和调用它的所有方法和属性。

(1) 获取Class对象的方式(3种)

//1.Class类的静态方法+全限类名
Class cls1 = Class.forName("company.group.name.Person");
//2.类名.class
Class cls2 = Person.class;
//3.Object类中的getClass()
Person p = new Person();
Class cls3 = p.getClass();

(2)反射创建类对象(2种)

  • Class的newInstance方法底层还是调用 无参构造器的newInstance()方法
  • 如果该类没有无参构造器或者不是public,Class.newInstance()无法使用,会有异常
Person p = new Person();
Class cls = p.getClass();

//1.利用Class自带的newInstance()
Person p1 = (Person)cls.newInstance();

//2.先获取构造器,再创建对象
Constructor con1 = cls.getConstructor(); //调用无参
Person p2 = (Person)con1.newInstance();

Constructor con2 = cls.getConstructor(String.class, int.class); //调用有参
Person p2 = (Person)con2.newInstance(“李四”,25);

(3)反射获取field

  • getFields()无法获取私有属性,只能获取 public属性 + 父类属性
  • getDeclaredFields() 可以获取包括private在内的所有自定义属性(仅仅获取属性名,无法获取值或修改值)
  • field.setAccessible(true):可以对private的get和set操作
Field getField(String name) //获得命名的公共字段 
Field[] getFields() //获得类的所有公共字段 
Field getDeclaredField(String name) //获得类声明的命名的字段 
Field[] getDeclaredFields() //获得类声明的所有字段

//例子
Class cls = Person.class;
Field f = cls.getField("name");

Person p = new Person("张三",25);
Object value = f.get(p);
f.set(p, “李四”);

(4)反射获取方法

  • 调用Method类的invoke()方法
Method getMethod(String name, Class[] params) //(方法名,参数1,参数2...)
Method[] getMethods() //获得类的所有public方法 + 父类方法
Method getDeclaredMethod(String name, Class[] params) //所有修饰符的方法(不含父类)
Method[] getDeclaredMethods() //所有方法(不含父类)

Class cls = Person.class;
Method eat1 = cls.getClass("eat")   // 获取eat()方法
Method eat2 = cls.getClass("eat",String.class)  //获取eat(String name)方法

Person p = new Person();
eat1.invoke(p);     //执行p的eat()方法
eat2.invoke(p, "大饼");       //执行p的eat("大饼")方法
String name = eat1.getName();     //获取"eat"

(5)反射获取构造器

Constructor getConstructor(Class[] params)  //(参数1,参数2...)
Constructor[] getConstructors() 
Constructor getDeclaredConstructor(Class[] params)  //所有修饰符的构造器
Constructor[] getDeclaredConstructors() //所有修饰符的构造器

Class cls = Person.class;
Constructor con1 = cls.getConstructor();
Constructor con2 = cls.getConstructor(String.class, int.class);
Person per1= (Person)con1.newInstance();
Person per2= (Person)con2.newInstance(“张三”, 25);

(6)反射获取泛型



(7)反射获取注解

  • getAnnotation() 和 getDeclaredAnnotation()方法

2. 注解

  • 注解作用
  • 编写API文档:代码里进行注释,javadoc命令生成对应的API文档
  • 编译检查:如Override检查
  • 代码分析:反射
  • 注解本质
public @interface MyTestAnnotation {}

(1)JDK内置注解,没啥大用处

@Override:检测该方法是否是继承自父接口
@Deprecated:标注该内容已过时,不建议使用
@SuppressWarnings:压制警告,例如在eat()方法上加上该注解,关于该方法编译阶段的警告(如never used)都不会出现

(2)元注解(5种):用来修饰注解的注解

  • @Retention:它表示注解存在阶段是保留在源码(编译期),字节码(类加载)或者运行期(JVM中运行)
//@Retention(RetentionPolicy.SOURCE),注解仅存在于源码中,在class字节码文件中不包含
//@Retention(RetentionPolicy.CLASS), 默认的保留策略,注解会在class字节码文件中存在,但运行时无法获得
//@Retention(RetentionPolicy.RUNTIME), 注解会在class字节码文件中存在,在运行时可以通过反射获取到
//注:自己定义的注解一般都用RUNTIME
@Retention(RetentionPolicy.RUNTIME)
public @interface MyTestAnnotation {

}
  • @Target:它表示我们的注解作用的范围,可以是类,方法,方法参数变量等
//@Target(ElementType.TYPE) 作用接口、类、枚举、注解
//@Target(ElementType.FIELD) 作用属性字段、枚举的常量
//@Target(ElementType.METHOD) 作用方法
//@Target(ElementType.PARAMETER) 作用方法参数
//@Target(ElementType.CONSTRUCTOR) 作用构造函数
//@Target(ElementType.ANNOTATION_TYPE)作用于注解(@Retention注解中就使用该属性)
//一般比较常用的是ElementType.TYPE类型
@Target(ElementType.TYPE)
public @interface MyTestAnnotation {

}
  • @Documented:它的作用是能够将注解中的元素包含到 Javadoc 中去
  • @Inherited:表示它的子类也继承了父类的注解
  • @Repeatable(JDK1.8加入):这个元注解修饰的注解可以同时作用一个对象多次,但是每次作用注解又可以代表不同的含义,见Reference

(3)注解的属性

  • 可以有以下类型
  • 8种基本数据类型
  • String
  • 枚举类
  • 注解类
  • Class类
  • 以上类型的一维数组类
  • 可以用default关键字设置初始化值,数组赋值时,可以用{}
  • 如果只有一个属性需要赋值,且名称是value,则可以省略不写
@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MyTestAnnotation {
    String name() default "mao";
    int age() default 18;
}

@MyTestAnnotation(name = "father", age = 50)
public class Father {
}

(4)注解的本质:Annotation接口的子接口

本质:继承Annotation接口的子接口
public interface 注解名称 extends java.lang.annotation.Annotation{}

/**Annotation接口源码*/
public interface Annotation {
    boolean equals(Object obj);
    int hashCode();
    Class<? extends Annotation> annotationType();
}

Reference

注解:https://www.jianshu.com/p/9471d6bcf4cf


 


2.4 注解与反射