目录

  • 注解
  • 反射


注解

注解可以标记在包、类、属性、方法,方法参数以及局部变量上,且同一个地方可以同时标记多个注解。注解最常见的应用是可以通过反射技术去得到类里面的注解,以决定怎么去运行类。

负责注解其他注解的注解,java的四个元注解

1.@Target:描述注解的使用范围,即用在类、方法、变量,它的取值范围定义在ElementType 枚举中。

public enum ElementType {
	// 类、接口、枚举类
    TYPE, 
    // 成员变量(包括:枚举常量)
    FIELD, 
    // 成员方法
    METHOD, 
    // 方法参数
    PARAMETER, 
    // 构造方法
    CONSTRUCTOR, 
    // 局部变量
    LOCAL_VARIABLE, 
    // 注解类
    ANNOTATION_TYPE, 
    // 可用于修饰:包
    PACKAGE, 
    // 类型参数,JDK 1.8 新增
    TYPE_PARAMETER, 
    // 使用类型的任何地方,JDK 1.8 新增
    TYPE_USE 
}

2.@Retention:表示在什么级别保存该注释信息,用于描述注解的生命周期,定义在RetentionPolicy枚举中。(SOURCE<CLASS<RUNTIME)

public enum RetentionPolicy {
    // 源文件保留
    SOURCE,    
    // 编译期保留,默认值
    CLASS,     
    // 运行期保留,可通过反射去获取注解信息 
    RUNTIME   
}

3.@Documented:说明该注解将被包含在javadoc帮助文档中,没有此注解则不会保留。

4.@Inherited:说明子类可以继承父类中的该注解,比方一个类使用了被@Inherited修饰的注解,则其子类将自动具有该注解。

自定义注解测试:

@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnoation {
    //参数类型+参数名
    String name() default "";
    int age() default 0;
    //如果值为默认值-1,代表不存在
    int id() default -1;
    //value才可以省略
    String[] schools() default {"北京大学"};
}

反射

利用反射读取注解,可以理解为逆着来,以前是从类创建对象,现在从对象获取到类的结构,甚至方法,属性。

reflection是java被视为动态语言的关键,反射机制允许程序在执行期间,借助Reflection API取得任何类的内部信息,并能直接操作任意对象的的内部属性及方法。

类加载器在加载类的时候,是将.class文件里的二进制数据读取到内存中,将其放在方法区中,然后再在堆内存中创建.Class对象,用来封装类的数据结构,加载类的最终产物是堆内存中的Class对象,我们可以通过这个.Class对象看到类的结构,这个对象就像一面镜子,透过这个镜子可以看到类的结构,所以称之为反射。

打印的结果为true,可以知道只有一个class对象加载到内存中

测试User类:

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private String name;
    private int id;
    private int age;
}

测试字节码文件是否一致:

public static void main(String[] args) throws ClassNotFoundException {
        Class c1 = Class.forName("com.mytest.test.model.User");
        Class c2 = Class.forName("com.mytest.test.model.User");
        System.out.println(c1==c2);
    }

打印结果为true。

Java怎么查看注解生效了 java注解获取被注解的字段_反射


测试获取类的属性,getFields方法只能获取public修饰的属性,getDeclaredFields可以获取所有的

public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {
        Class<?> c = Class.forName("com.mytest.test.model.User");
        Field[] fields = c.getFields();
        fields = c.getDeclaredFields();
        for (Field field : fields) {
            System.out.println(field);
        }
        
        Method getName = c.getMethod("getName", null);
        Method setName = c.getMethod("setName", String.class);
        System.out.println(getName);
        System.out.println(setName);

        Constructor[] constructors = c.getConstructors();
        for (Constructor constructor : constructors) {
            System.out.println(constructor);
        }
    }

打印结果:

Java怎么查看注解生效了 java注解获取被注解的字段_System_02

通过反射获取注解及里面的参数

注意事项:

  1. 如果获取的是类的注解,直接从类的class对象中获取注解,再通过注解获取里面的参数
  2. 如果是获取方法或者属性的注解,先中类的class对象中获取方法或者属性,再获取里面的参数。
  • getDeclaredFields:获取属性
  • getAnnotation:获取注解
@Slf4j
public class Test {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {
        Class<?> c = Class.forName("com.mytest.test.User2");
        Annotation[] annotations = c.getAnnotations();
        for (Annotation annotation : annotations) {
            System.out.println(annotation);
        }
        TableKuang tableKuang = c.getAnnotation(TableKuang.class);
        String value = tableKuang.value();
        System.out.println(value);

        Field[] declaredFields = c.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            FieldKuang annotation = declaredField.getAnnotation(FieldKuang.class);
            System.out.println(annotation);
            System.out.println(annotation.columnName());
            System.out.println(annotation.length());
            System.out.println(annotation.type());
        }
    }
}

//类名的注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface TableKuang {
    String value();
}

//属性的注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface FieldKuang {
    String columnName();

    String type();

    int length();
}

@Data
@AllArgsConstructor
@NoArgsConstructor
@TableKuang("测试user")
class User2 {
    @FieldKuang(columnName = "name注解", type = "String注解",length = 11)
    private String name;

    @FieldKuang(columnName = "id注解", type = "int注解",length = 12)
    private int id;

    @FieldKuang(columnName = "age注解", type = "int注解",length = 13)
    private int age;
}

打印结果:

Java怎么查看注解生效了 java注解获取被注解的字段_java_03