Java注解之获取注解内部数据的原因分析

我们都知道从JDK1.5开始,注解开始被支持使用,当我们在使用注解的时候感觉比配置文件用起来更加简便和清爽。配置文件是通过解析配置文件的内容获取到数据,那么为什么仅仅在类、方法或者属性上添加注解被注解对象就内部就能获取到注解内部的数据了呢?

一、给类添加单个注解

1、自定义一个注解:

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @Classname Pro
 * @Description TODO
 * @Date 2020/9/16 17:27
 * @Created by Administrator
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Pro {
    String className();
    String methodName();
}
View Code

2、定义一个类用于测试类通过反射创建对象调用其内部方法

/**
 * @Classname User
 * @Description TODO
 * @Date 2020/9/16 17:28
 * @Created by Administrator
 */
public class User {
    public void eat(){
        System.out.println("吃饭...");
    }

    public void drink(){
        System.out.println("喝水...");
    }
}
View Code

3、定义一个测试类用于测试注解内数据是如何被获取到的

import java.lang.reflect.Method;

/**
 * @Classname AnnotationClassTest
 * @Description TODO
 * @Date 2020/9/16 17:29
 * @Created by Administrator
 */
@Pro(className = "User",methodName = "eat")
public class AnnotationClassTest {
    public static void main(String[] args) throws Exception {
        // 1 获取被注解位置的字节码对象
        Class<AnnotationClassTest> testClass = AnnotationClassTest.class;
        // 2 根据注解的字节码对象创建注解对象
        Pro annotation = testClass.getAnnotation(Pro.class);
        // 3 根据注解对象获取注解内部数据
        String className = annotation.className();
        String methodName = annotation.methodName();
        // 3.1打印获取到的注解数据
        System.out.println(className);
        System.out.println(methodName);
        // 4 通过反射通过获取到的className获取该类字节码对象
        Class aClass = Class.forName(className);
        // 5 通过该字节码对象根据获取到的methodName获取方法对象
        Method method = aClass.getMethod(methodName);
        // 6 通过类字节码对象生成该类对象
        User user= (User) aClass.newInstance();
        // 7 方法执行
        method.invoke(user);
    }
}
View Code

二、给方法添加单个注解

1、自定义一个注解

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @Classname Pro
 * @Description TODO
 * @Date 2020/9/16 17:27
 * @Created by Administrator
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Pro2 {
    String className();
    String methodName();
}
View Code

2、定义一个类用于测试类通过反射创建对象调用其内部方法

/**
 * @Classname User
 * @Description TODO
 * @Date 2020/9/16 17:28
 * @Created by Administrator
 */
public class User {
    public void eat(){
        System.out.println("吃饭...");
    }

    public void drink(){
        System.out.println("喝水...");
    }
}
View Code

3、定义一个测试类用于测试注解内数据是如何被获取到的

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

/**
 * @Classname AnnotationClassTest
 * @Description TODO
 * @Date 2020/9/16 17:29
 * @Created by Administrator
 */

public class AnnotationMethodTest {
    @Pro2(className = "User",methodName = "eat")
    public static void main(String[] args) throws Exception {
        // 1 获取被注解位置的字节码对象
        Class<AnnotationMethodTest> testClass = AnnotationMethodTest.class;
        // 2 根据注解的字节码对象创建注解对象
        Pro2 annotation = testClass.getMethod("main", String[].class).getAnnotation(Pro2.class);
        // 3 根据注解对象获取注解内部数据
        String className = annotation.className();
        String methodName = annotation.methodName();
        // 4 通过反射通过获取到的className获取该类字节码对象
        Class aClass = Class.forName(className);
        // 5 通过该字节码对象根据获取到的methodName获取方法对象
        Method method = aClass.getMethod(methodName);
        // 6 通过类字节码对象生成该类对象
        User user= (User) aClass.newInstance();
        // 7 方法执行
        method.invoke(user);
    }
}
View Code

三、给类添加多个注解

1、自定义两个注解

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @Classname Pro
 * @Description TODO
 * @Date 2020/9/16 17:27
 * @Created by Administrator
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Pro {
    String className();
    String methodName();
}
自定义注解1
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @Classname Pro
 * @Description TODO
 * @Date 2020/9/16 17:27
 * @Created by Administrator
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Pro3 {
    String className();
    String methodName();
    String age();
}
自定义注解2

2、定义一个类用于测试类通过反射创建对象调用其内部方法

/**
 * @Classname User
 * @Description TODO
 * @Date 2020/9/16 17:28
 * @Created by Administrator
 */
public class User {
    public void eat(){
        System.out.println("吃饭...");
    }

    public void drink(){
        System.out.println("喝水...");
    }
}
View Code

3、定义一个测试类用于测试注解内数据是如何被获取到的

import java.lang.reflect.Method;

/**
 * @Classname AnnotationClassTest
 * @Description TODO
 * @Date 2020/9/16 17:29
 * @Created by Administrator
 */
@Pro(className = "User",methodName = "eat")
@Pro3(className = "User",methodName = "drink",age = "23")
public class AnnotationClassTest2 {
    public static void main(String[] args) throws Exception {
        // 1 获取被注解位置的字节码对象
        Class<AnnotationClassTest2> testClass = AnnotationClassTest2.class;
        Pro annotation = testClass.getAnnotation(Pro.class);
        String className = annotation.className();
        String methodName = annotation.methodName();
        Class aClass = Class.forName(className);
        Method method = aClass.getMethod(methodName);
        User user= (User) aClass.newInstance();
        method.invoke(user);

        Pro3 annotation2 = testClass.getAnnotation(Pro3.class);
        String className2 = annotation2.className();
        String methodName2 = annotation2.methodName();
        Class aClass2 = Class.forName(className2);
        Method method2 = aClass2.getMethod(methodName2);
        User user2= (User) aClass2.newInstance();
        method2.invoke(user2);
    }
}
View Code

总结

之所以被注解内部能够获取注解内部数据根本原因就在于通过被注解对象字节码文件能够获取到该对象字节码文件中是否含有注解,并能够通过该字节码文件获取注解内部数据,因此更简便的实现了配置文件相同的功能。
原文地址:https://www.cnblogs.com/sun-10387834/p/13683436.html