Java 注解
创始人
2024-03-24 22:33:11
0

目录

一、简介

二、注解分类

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{@Overridepublic 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 示例的检查。

相关内容

热门资讯

AWSECS:访问外部网络时出... 如果您在AWS ECS中部署了应用程序,并且该应用程序需要访问外部网络,但是无法正常访问,可能是因为...
银河麒麟V10SP1高级服务器... 银河麒麟高级服务器操作系统简介: 银河麒麟高级服务器操作系统V10是针对企业级关键业务...
【NI Multisim 14...   目录 序言 一、工具栏 🍊1.“标准”工具栏 🍊 2.视图工具...
不能访问光猫的的管理页面 光猫是现代家庭宽带网络的重要组成部分,它可以提供高速稳定的网络连接。但是,有时候我们会遇到不能访问光...
AWSElasticBeans... 在Dockerfile中手动配置nginx反向代理。例如,在Dockerfile中添加以下代码:FR...
月入8000+的steam搬砖... 大家好,我是阿阳 今天要给大家介绍的是 steam 游戏搬砖项目,目前...
​ToDesk 远程工具安装及... 目录 前言 ToDesk 优势 ToDesk 下载安装 ToDesk 功能展示 文件传输 设备链接 ...
北信源内网安全管理卸载 北信源内网安全管理是一款网络安全管理软件,主要用于保护内网安全。在日常使用过程中,卸载该软件是一种常...
AWS管理控制台菜单和权限 要在AWS管理控制台中创建菜单和权限,您可以使用AWS Identity and Access Ma...
AWR报告解读 WORKLOAD REPOSITORY PDB report (PDB snapshots) AW...