一篇文章弄懂注解

标签: java基础  反射  注解

注解:注解是附加在代码的一些信息,用于一些工具在编译、运行时进行解析和使用,起到说明、配置的功能。注解不会影响代码的实际逻辑,仅仅起到辅助作用。
注解的三种分类:

1.自定义注解:比如 @Controller,@Service,@Table等等,是开发者定义的注解。
2.元注解:jdk的注解,有四个:@Target,@Inherited ,@Retention,@Documented。
3.内置注解:jdk除了四个元注解之前的注解,如@Override,@SuppressWarnings等

自定义注解:

自定义注解流程:
自定义注解很简单:选择ide,创建annotation取名即可。
在这里插入图片描述
然后我们的自定义注解就创建成功啦。

package com.jym.demo.bean;

public @interface MyAnnotation {
}

当然 我们还可以给注解添加属性。注解里定义属性,跟类中的方法类似,需要加括号,如果属性没有默认值,则被注解修饰的类上,必须定义值,否则编译不通过。

package com.jym.demo.bean;

public @interface MyAnnotation {

    // 注解属性
    String name();                        // 被修饰的类必须给name属性赋值,否则会报错
    int age() default 25;                 // 默认值为25
    String hello() default "hello,world"; // 默认值为hello,world
    
}

元注解:

[email protected]:定义了注解的生命周期,注解的生命周期有三个阶段:

@Retention(RetentionPolicy.SOURCE):
注解会保留在源码里,但是编译成class文件后不会出现,即为注解的第一阶段。@Override、@SuppressWarnings都属于这类注解,可以做一些检查性的操作;
@Retention(RetentionPolicy.CLASS):
注解会保留在源码,以及编译后的class文件中,但是不会保留在JVM中,为注解的第二阶段,同样注解也是默认使用这种方式
@Retention(RetentionPolicy.RUNTIME):注解的第三阶段,存在于源码,class文件,以及jvm中,因此我们可以通过反射拿到该注解的信息,我们自定义注解通常使用这种方式,@Deprecated属于此类注解。
具体的反射方式:
注解:

package com.jym.demo.bean;

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

@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {

    // 注解属性
    String name();                        // 被修饰的类必须给name属性赋值,否则会报错
    int age() default 25;                 // 默认值为25
    String hello() default "hello,world"; // 默认值为hello,world

}

被注解修饰的类:

@MyAnnotation(name = "jym")
public class Person {}

测试方法:

    public static void main(String[] args) {
        Class<Person> clazz = Person.class;
        if(clazz.isAnnotationPresent(MyAnnotation.class)){
            MyAnnotation myAnnotation = clazz.getAnnotation(MyAnnotation.class);
            System.out.println(myAnnotation.name()+":"+myAnnotation.age());
        }
    }

结果:

jym:25
2. @Target:设置作用目标,使用范围:

@Target(ElementType.TYPE) :用于接口、类、枚举、注解
@Target(ElementType.FIELD) :字段、枚举的常量
@Target(ElementType.METHOD) :方法
@Target(ElementType.PARAMETER) :方法参数
@Target(ElementType.CONSTRUCTOR) :构造函数
@Target(ElementType.LOCAL_VARIABLE) :局部变量
@Target(ElementType.ANNOTATION_TYPE) :注解
@Target(ElementType.PACKAGE) :包
具体反射流程:
注解:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface MyAnnotation {

    // 注解属性
    String name();                        // 被修饰的类必须给name属性赋值,否则会报错
    int age() default 25;                 // 默认值为25
    String hello() default "hello,world"; // 默认值为hello,world

}

修饰类:

public class Person {

    private int age;
    @MyAnnotation(name = "jym")
    private String name;
    private Date birth;
}

测试方法:

    public static void main(String[] args) {
        Class<Person> clazz = Person.class;
        Field[] declaredFields = clazz.getDeclaredFields(); // 获取所有字段
        for (Field declaredField : declaredFields) {
            MyAnnotation annotation = declaredField.getAnnotation(MyAnnotation.class);
            if(annotation!=null){
                System.out.println("姓名:"+annotation.name());
            }
        }

结果:

姓名:jym
3. @Document :

说明该注解将被包含在javadoc中,至于javadoc,就是通过Javadoc技术,从程序源代码中抽取类、方法、成员等注释形成一个和源代码配套的API帮助文档。需要更多了解的,请百度一下。

4. @Inherited :

继承性,加上这个注解,别的类在继承被该注解修饰的类时,会自动加上这个注解。通过反射也是可以拿到的。

这里说明一下反射的方法:

getFields()方法获得某个类的所有的public的字段,包括父类。getDeclaredFields()获得某个类的所有申明的字段,即包括public、private和proteced,但是不包括父类的申明字段。同样类似的还有getConstructors()和getDeclaredConstructors(),getMethods()和getDeclaredMethods()。如果感兴趣的,可以在控制台打印一下。

内置注解:

java的一切注解都是基于元注解的
@Override(重写父类方法)
@SuppressWarning(阻止警告)
@FunctionaInterface(指定接口函数式编程)
@SafeVarargs(堆污染警告)
在SpringMVC中,就是通过对controller修饰的类进行反射,将注解里的值存进MAP里,核心servlet才能找到对应的类中的对应方法所执行

世界上有10种人,一种是懂二进制的,一种是不懂二进制的。

感谢您的收看,如有哪里写的不对 请留言,谢谢。

原文链接:加载失败,请重新获取