Java - 注解与反射(个人总结,仅供参考)

1. 注解


注解的本质实际上是一个类。所有的注解都继承于Annotation这个基类。它是一个标注,可以标注在字段、方法、类、注解上,以此来为被标注的元素拓展额外的辅助信息。

- 元注解

Java中定义了4个元注解,用来负责修饰其他的注解。

1. @Target:用于描述被它所修饰的注解的使用范围

  • ElementType.TYPE:可以修饰类、接口、枚举、注解

  • ElementType.CONSTRUCTOR:可以修饰构造函数

  • ElementType.FIELD:可以修饰字段

  • ElementType.LOCAL_VARIABLE:可以修饰局部变量

  • ElementType.METHOD:可以修饰方法

  • ElementType.PACKAGE:可以修饰包

  • ElementType.PARAMETER:可以修饰方法参数

  • ElementType.ANNOTATION_TYPE:可以修饰注解

2. @Retention:用于描述被他所修饰的注解的生命周期

  • SOURCE:被修饰的注解只在源代码中存在

  • CLASS:被它修饰的注解在class字节码文件中存在(在运行前存在)

  • RUNTIME:被它修饰的注解直到运行时也依旧存在

3. @Document:被他所修饰的注解会被包含在Javadoc中

  • 被它修饰的注解会存在于它所对应的Javadoc文档中

4. @Inherited:被它所修饰了的类的子类,可以继承父类的注解

  • 使用@Inherited
public class Test {
    public static void main(String[] args) throws ClassNotFoundException {
        Class c = Class.forName("B");
        MyAnnotation annotation = (MyAnnotation) c.getAnnotation(MyAnnotation.class);
        if(annotation!=null)
            System.out.println(annotation.value());
        else
            System.out.println("None");
        //运行结果:XiaoJie
    }

}

@Retention(RetentionPolicy.RUNTIME)
@Inherited
@interface MyAnnotation{
    String value();
}

@MyAnnotation("XiaoJie")
class A{}

class B extends A{}
  • 不使用@Inherited
public class Test {
    public static void main(String[] args) throws ClassNotFoundException {
        Class c = Class.forName("B");
        MyAnnotation annotation = (MyAnnotation) c.getAnnotation(MyAnnotation.class);
        if(annotation!=null)
            System.out.println(annotation.value());
        else
            System.out.println("None");
        //运行结果:None
    }

}

@Retention(RetentionPolicy.RUNTIME)
//@Inherited
@interface MyAnnotation{
    String value();
}

@MyAnnotation("XiaoJie")
class A{}

class B extends A{}

2. 反射


  • JAVA反射机制是在运行状态中,对于任意一个实体类,都能够知道这个类的所有属性和方法;

  • 对于任意一个对象,都能够调用它的任意方法和属性;

  • 这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。

Class类:

  • Java的反射机制和一个叫Class类的玩意儿有着紧密的联系。在Java中的每一个类,当它被加载的时候,都会产生一个与它唯一对应的Class类实例。不管这个类的实例有多少,它的Class类实例,或者说这些实例对应的Class类实例有且只有一个。

  • 我们可以通过类、类名、类的实例来获取它们所对应的Class类的实例。

  • 当我们得到Class类的实例时,我们就可以通过这个实例来访问它所对应的这个类的任意方法、字段以及注解。

Class类加载时机:

当程序主动引用某个类的时候,如果该类还未被加载到内存中,则系统会经过加载、链接、初始化三个阶段来对类进行加载。而它所对应的Class类会在加载阶段被进行创建。

什么时候会被视为主动引用:
  • new一个类的时候
  • 调用类的静态成员和静态方法的时候
  • 通过反射来对类进行调用的时候
  • 子类被加载的时候

参考代码:

public class Program {

    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException {

//===========获取Class对象的几种方式===========
        //通过Class对象创建对应类的实例
        Student student = Student.class.getDeclaredConstructor().newInstance();
        student.getScore().put("English",100);
        student.getScore().put("Math",100);
        student.getScore().put("Chinese",100);

        Class cStudent1 = Class.forName("Student");
        Class cStudent2 = Student.class;
        Class cStudent3 = student.getClass();

//===========通过Class对象获取字段的信息===========
        System.out.println("获取字段的信息:");
        System.out.println(cStudent1.getDeclaredField("Name"));
        System.out.println(cStudent1.getDeclaredField("ID"));
//===========通过Class对象获取泛型的信息===========
        System.out.println("获取泛型的信息:");
        Field score = cStudent1.getDeclaredField("Score");
        Type genericType = score.getGenericType();
        if(genericType instanceof ParameterizedType){
            Type[] actualTypeArguments =
                    ((ParameterizedType) genericType).getActualTypeArguments();
            for(var item : actualTypeArguments) System.out.println(item);
        }
//===========通过Class对象获取注解的信息===========
        System.out.println("获取注解的信息:");
        MyAnnotation annotation =
                (MyAnnotation) cStudent1.getAnnotation(MyAnnotation.class);
        System.out.println(annotation.value());
//===========通过Class对象获取方法的信息===========
        System.out.println("获取方法的信息:");
        Method showInformation = cStudent1.getMethod("ShowInformation");
        showInformation.invoke(student);

/*       运行结果如下:
 *       -----------------------------------------------------------------
 *       获取字段的信息:
 *       private java.lang.String Student.Name
 *       private java.lang.String Student.ID
 *       获取泛型的信息:
 *       class java.lang.String
 *       class java.lang.Integer
 *       获取注解的信息:
 *       XiaoJieInformation
 *       获取方法的信息:
 *       ========ShowInformation方法开始执行========
 *       XiaoJie
 *       123
 *       English:100
 *       Chinese:100
 *       Math:100
 *       ========ShowInformation方法执行结束========
 *
 *       Process finished with exit code 0
 */
    }
}

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation{
    String value();
}

@MyAnnotation("XiaoJieInformation")
class Student{
    private String Name="XiaoJie";
    private String ID="123";
    private Map Score=new HashMap();

    public Map getScore() {
        return Score;
    }

    public void ShowInformation(){
        System.out.println("========ShowInformation方法开始执行========");
        System.out.println(Name);
        System.out.println(ID);
        for(var item : Score.entrySet())
            System.out.println(item.getKey()+":"+item.getValue());
        System.out.println("========ShowInformation方法执行结束========");
    }
}

你可能感兴趣的:(Java - 注解与反射(个人总结,仅供参考))