Java 注解

目录

一、简介

二、注解分类

2.1、由编译器使用的注解

2.2、由工具处理.class 文件的注解

2.3、程序运行期能够读取到注解,加载后一直存在 JVM 的注解

三、定义注解

3.1、元注解

3.2、注解配置参数类型

3.3、@Target

3.4、@Retention

3.5、@Repeatable

3.6、@Inherited

3.7、定义注解        

3.7.1、用@interface 定义注解

3.7.2、添加参数和默认值

3.7.3、用元注解配置注解

四、处理注解

4.1、使用注解


一、简介

        注解是放在 Java 源码类、方法、字段、参数前的一种特殊 ”注释“ 。

        注释是被编译器直接忽略,注解则可以被编译器打包进 class 文件,因此,注解是一种用作标注的 ”元数据“。

二、注解分类

        从 JVM 的角度看,注解本身对代码逻辑没有任何影响,如何使用注解完全由工具决定。

2.1、由编译器使用的注解

        例如:

        @Override:让编译器检查该方法是否正确地实现了覆写。
        @SuppressWarnings:告诉编译器忽略此处代码产生的警告。

        这类注解救不活被编译进入 .class 文件,它们在编译后就被编译器扔掉了。

        示例        

       Main.java 类


public class Main{

    public static void main(String[] args) {
        A a = new B();
        a.say();
    }

}

interface A{
    void say();
}
class B implements A{

    @Override
    public void say() {

    }
}

       编译后的文件

        Main.class

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

public class Main {
    public Main() {
    }

    public static void main(String[] args) {
        A a = new B();
        a.say();
    }
}

        A.class

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

interface A {
    void say();
}

        B.class

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

class B implements A {
    B() {
    }

    public void say() {
    }
}

        B.class 文件里 @Override 注解编译后就被编译器扔掉了。

2.2、由工具处理.class 文件的注解

        比如工具会在加载class的时候,对class做动态修改,实现一些特殊功能。

        例如:

        @Data   IntelliJ IDEA 工具可以自动生成get与set方法并且重写equals和toString方法

        示例

        Person.java

import lombok.Data;

@Data
public class Person {

    private String username;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }
}

        Person.class

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

public class Person {
    private String username;

    public String getUsername() {
        return this.username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public Person() {
    }

    public boolean equals(Object o) {
        if (o == this) {
            return true;
        } else if (!(o instanceof Person)) {
            return false;
        } else {
            Person other = (Person)o;
            if (!other.canEqual(this)) {
                return false;
            } else {
                Object this$username = this.getUsername();
                Object other$username = other.getUsername();
                if (this$username == null) {
                    if (other$username != null) {
                        return false;
                    }
                } else if (!this$username.equals(other$username)) {
                    return false;
                }

                return true;
            }
        }
    }

    protected boolean canEqual(Object other) {
        return other instanceof Person;
    }

    public int hashCode() {
        int PRIME = true;
        int result = 1;
        Object $username = this.getUsername();
        int result = result * 59 + ($username == null ? 43 : $username.hashCode());
        return result;
    }

    public String toString() {
        return "Person(username=" + this.getUsername() + ")";
    }
}

2.3、程序运行期能够读取到注解,加载后一直存在 JVM 的注解

        在程序运行期能够读取的注解,它们加载后一直存在于 JVM 中, 这也是最常用的注解。

        例如:

        @Controller  Spring 标记控制类注解

        @Service   Spring 标记业务层注解

@Controller
public class ApiController {
}

         ApiController.java文件 和 编译后文件ApiController.class 是一样的。@Controller 也一直存在。

三、定义注解

        Java 语言使用 @Interface 语法来定义注解(Annotation)。

        示例

public @interface Report {
    int type() default 0;

    String level() default "info";

    String value() default "";
}

        注解参数类似无参数方法,可以用 default 设置一个默认值(推荐)。比较常用参数名为value 。

3.1、元注解

        有一些注解可以修饰其他的注解,这些注解就称为元注解(meta annotation)。Java 标准库已经定义了一些元注解,只需使用注解,通常不需要自己写元注解。

3.2、注解配置参数类型

        定义一个注解时,还可以配置参数,配置参数可以包括

  •         Java基本类型
  •         String
  •         枚举类型
  •         基本类型、String、Class以及枚举的数组

3.3、@Target

        最常用的元注解是 @Target 。作用是定义的注解能够应用源码的哪些位置。

  •         类或接口:ElementType.TYPE
  •         字段:ElementType.FIELD
  •         方法:ElementType.METHOD
  •         构造方法:ElementType.CONSTRUCTOR
  •         方法参数:ElementType.PARAMETER 

        示例

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

@Target({
        ElementType.METHOD,
        ElementType.FIELD
})
public @interface Report {
}

        定义注解 Report 可以使用在方法和字段上。

3.4、@Retention

        @Retention 作用是定义注解的生命周期。

  •         仅编译期:RetentionPolicy.SOURCE
  •         仅class文件:RetentionPolicy.CLASS
  •         运行期:RetentionPolicy.RUNTIME

        如果注解@Retention不存在,默认 仅class文件:RetentionPolicy.CLASS 。通常自定义注解都是运行期RetentionPolicy.RUNTIME这个元注解。

        示例

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

@Retention(RetentionPolicy.RUNTIME)
public @interface Report {
    int type() default 0;
    String level() default "info";
    String value() default "";
}

3.5、@Repeatable

        @Repeatable作用是这个注解是否可以重复使用。

        示例

import java.lang.annotation.ElementType;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Target;

@Report(type=1, level="debug")
@Report(type=2, level="warning")
public class Main{

    public static void main(String[] args) {

    }



}
@Repeatable(Reports.class)
@Target(ElementType.TYPE)
@interface Report {
    int type() default 0;
    String level() default "info";
    String value() default "";
}

@Target(ElementType.TYPE)
@interface Reports {
    Report[] value();
}

3.6、@Inherited

        @Inherited作用 子类是否可以继承父类定义的注解。注意@Inherited只对@Target(ElementType.TYPE)类型的注解有效,并且对继承的类有效,对接口的继承无效。

        示例

import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Target;

@Inherited
@Target(ElementType.TYPE)
public @interface Report {
    int type() default 0;
    String level() default "info";
    String value() default "";
}

        在使用的时候,如果一个类用到了@Report

@Report(type=1)
public class Person {
}

        则它的子类默认也定义了该注解:

public class Student extends Person {
}

3.7、定义注解        

3.7.1、用@interface 定义注解

public @interface Report {
}

3.7.2、添加参数和默认值

public @interface Report {
    int type() default 0;
    String level() default "info";
    String value() default "";
}

3.7.3、用元注解配置注解

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

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Report {
    int type() default 0;
    String level() default "info";
    String value() default "";
}

        其中必须设置@Target 和@Retention 。 @Retention 一般设置为运行期(RetentionPolicy.RUNTIME),@Inherited 和 @ Repeatable一般可以不写。

四、处理注解

        判断某个注解是否存在于类、字段、方法或构造器。

  •         Class.isAnnotationPresent(Class)
  •         Field.isAnnotationPresent(Class)
  •         Method.isAnnotationPresent(Class)
  •         Constructor.isAnnotationPresent(Class)

        示例

// 判断@Report是否存在于Person类:
Person.class.isAnnotationPresent(Report.class);

         使用反射API读取注解

  •         Class.getAnnotation(Class)
  •         Field.getAnnotation(Class)
  •         Method.getAnnotation(Class)
  •         Constructor.getAnnotation(Class)

        示例

// 获取Person定义的@Report注解:
Report report = Person.class.getAnnotation(Report.class);
int type = report.type();
String level = report.level();

4.1、使用注解

        定义一个Range.java注解类。 

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

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Range {
    int min() default 0;
    int max() default 255;
}

        Person.java使用注解

public class Person {
    @Range(min=1, max=20)
    public String name;

    @Range(max=10)
    public String city;
}

        测试

import java.lang.reflect.Field;

public class Main{

    public static void main(String[] args) {
        Person p = new Person();
        p.name="张无忌";
        p.city="深圳";

        try {
            Main.check(p);
        } catch (ReflectiveOperationException e) {
            e.printStackTrace();
        }

    }

    static void check(Person person) throws IllegalArgumentException, ReflectiveOperationException {
        // 遍历所有Field:
        for (Field field : person.getClass().getFields()) {
            // 获取Field定义的@Range:
            Range range = field.getAnnotation(Range.class);
            // 如果@Range存在:
            if (range != null) {
                // 获取Field的值:
                Object value = field.get(person);
                // 如果值是String:
                if (value instanceof String) {
                    String s = (String) value;
                    // 判断值是否满足@Range的min/max:
                    if (s.length() < range.min() || s.length() > range.max()) {
                        throw new IllegalArgumentException("Invalid field: " + field.getName());
                    }
                }
            }
        }
    }




}

        通过@Range 注解,配合 check() 方法就可以完成Person 示例的检查。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

2014Team

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值