首页 > 图灵资讯 > 技术篇>正文

Java 注解

2023-04-21 10:06:21

注解

注解概述

  • Java注释(Annotation) 又称 Java 注释是JDK5.0引入的注释机制
  • Java语言中的类、构造器、方法、成员变量、参数等都可以标记
  • 注释不是程序的一部分,可以理解为注释是标签
  • 大多数时候,我们会使用注释,而不是自定义注释

JDK中预定义的一些注释

  • @Override:检测标注的方法是否继承了自父类(接口)
  • @Deprecated:标注的内容表示已过时
  • @Suppresswarnings: 压制警告[一般传输参数”all把它放在类上,如:@suppresswarnings("all")】

注解的作用

  • 标记Java中类、方法和成员变量,然后进行特殊处理。什么样的处理取决于业务需求
  • 例如,在JUnit框架中标记注释 @Test方法可以作为测试方法执行,没有标记的不能作为测试方法执行

注释给谁用?

  • 1、编译器
  • 2、使用解析程序

自定义注解

定制注释是指使用自己的注释

格式

                               Java 注解_System

(public为默认值,可省略)

注释本质上是一个接口,默认继承Annotation接口(注释反编译如下)

  • public interface 注解名 extends java,lang.annotation.Annotation {}

属性: 接口中的抽象方法要求

属性的返回值类型包括以下值(不包括类)

  • 基本数据类型
  • String
  • 枚举(类型为枚举类型,调用时为:枚举名.常量)
  • 注释(类型注释名,调用时为:定义时的变量名=@注释名)
  • 上述类型的数组

定义属性,使用时需要赋值属性

  • 如果在定义属性时使用default关键字默认初始化属性值,则在使用注释时不能赋予属性值
  • 如果只有一个属性需要赋值,属性的名称是value,value可以省略并直接定义值
  • 当数组赋值时,值使用 “{}” 包裹。若数组中只有一个值,则包裹。 “{}” 省略

我们先定义一个注释

 

public @interface AnnotationDemo {     String name()default "单身狗";}

 

我们已经写了默认值,这样在其他地方使用注释就不需要赋值了。如果我们想改名,也可以

 

@AnnotationDemopublic class ObjectDemo {    @AnnotationDemo(name = “单身狗1”    public static void main(            @AnnotationDemo            String[] args) {        @AnnotationDemo     String name="dog";    }}

 

我们对此时的注释没有约束,所以几乎可以在任何地方使用

但是,如果我们没有给出初始值,则每次使用注释时都需要输入值(只要符合定义的数据类型)

 

@AnnotationDemo(name = “单身狗”)public class ObjectDemo {    @AnnotationDemo(name = “单身狗”)    public static void main(            @AnnotationDemo(name = “单身狗”)            String[] args) {        @AnnotationDemo(name = “单身狗”)     String name="dog";    }}

 

特殊属性

  • value属性,如果只有一个value属性,在使用value属性时可以省略value名称
  • 但是,如果有多个属性,且多个属性没有默认值,则value名称不能省略

如下

 

public @interface AnnotationDemo {      String name()default "单身狗";      String value();}

 

然后,使用它的地方

 

@AnnotationDemo(“你好”)public class ObjectDemo {    @AnnotationDemo(“你好”)    public static void main(            @AnnotationDemo(“你好”)            String[] args) {        @AnnotationDemo(“你好”)        String name="dog";    }}

 

我们可以发现括号不需要写 "value=" 是的,但是当我们删除name的默认值时

 

public @interface AnnotationDemo {      String name();      String value();}

 

是必须要写 "value=" 的

 

@AnnotationDemo(value = "你好",name =“单身狗”)public class ObjectDemo {    @AnnotationDemo(value = "你好",name =“单身狗”)    public static void main(            @AnnotationDemo(value = "你好",name =“单身狗”)            String[] args) {        @AnnotationDemo(value = "你好",name =“单身狗”)        String name="dog";    }}

 


元注解

元注释是注释(动词)注释(名词)注释(名词)

常用元注:

  • @Target: 约束自定义注释可以标记的范围(即自定义注释可以在哪里使用)
  • @Retention: 用于约束自定义注释的生存范围(生命周期)(如:@Retention(RetentionPolicy.RUNTIME): 目前描述的注释将保留在class字节码文件中,并由JVM读取)
  • @Documented:描述注释是否被提取到api文档中(我们可以在文件所在的文档中启动终端,然后输入 javadoc API文档将生成相应的class文件)
  • @Inherited: 描述注解是否被子类继承(注解标记后,注解的子类继承也包括注解)

简单展示一下

 

@Target({ElementType.METHOD})//元注解,括号为限制范围(此限制注解仅用于方法)public @interface AnnotationDemo {}

 

@Target中可用的值定义Elementtype枚举常用值如下

范围

TYPE

类,接口

FIELD

成员变量

METHOD

成员方法

PARAMETER

方法参数

CONSTRUCTOR

构造器

LOCAL_VARIABLE

局部变量

@Retention中可用的值定义RetentionPolicy枚举常用值如下

范围

SOURCE

注释只作用于源代码阶段,生成的字节码文件中不存在

CLASS

注释在源代码阶段、字节码文件阶段、运行阶段不存在,默认值

RUNTIME

注释作用在源代码阶段、字节码文件阶段、运行阶段(常用开发)

两者结合格式

@Retention(RetentionPolicy.RUNTIME)@Target({ElementType.METHOD})public @interface AnnotationDemo {}

注解的解析

在注释操作中,经常需要进行分析。注释的分析是判断是否有注释。如果有注释,则分析内容

与注释分析相关的界面

  • Annotation:顶部接口的注释,Annotation类型的注释对象
  • AnnotatedElement:该界面定义了与注释分析相关的分析方法

方法

说明

Annotation[ ] getDeclaredAnnotations()

返回当前对象上使用的所有注释数组

T getDeclaredAnnotation(Class< T > annotationClass)

根据注解类型获得相应的注解对象 (实际上是在内存中生成注解接口的子类实现对象)(上述获取数组的相同性)

boolean isAnnotationPresent(Class< Annotation > annotationClass)

判断当前对象是否使用了指定的注释,如果使用,则返回true,否则false

Class,所有类成分,Method,Field,Constructor,都实现了Annnotatedelement接口,它们都有能力分析注释

分析注释的技巧:注释在哪个成分上,我们先拿哪个成分对象

  • 例如,注解作用成员方法,需要获得与成员方法对应的Method对象,然后取上述注解
  • 例如,如果注释作用于类别,则需要此类Class对象,然后取上述注释
  • 例如,如果注释作用于成员变量,则应获得成员变量对应的Field对象,然后取上述注释

我们用一个案例来理解这些技能和方法的使用

需求:注释分析案例

步骤分析

①定义注意Book,要求如下:

  • 包含属性: String value() 书名
  • 包含属性: double price() 价格,默认值为 100
  • 包含属性: String[ ] authors()多位作者
  • 限制注释的位置:类别和成员方法
  • 注释的有效范围:RUNTIME

② 定义BookStore类别,Book注释用于类和成员的方法

③定义AnnotationDemoBook注解上的数据获取测试类

代码展示

注释Book代码

@Retention(RetentionPolicy.RUNTIME)@Target({ElementType.TYPE,ElementType.METHOD})public @interface Book {    String value();    double price()default 100;    String[] authors();}

BookStore代码代码

@Book(value = “我真的不想重生”,price = 30,authors = {"柳暗花又明"}public class BookStore {    @Book(value = 漫画版《我真的不想重生》,price = 30,authors = {“噼啪”}    public static void buyBook(){        System.out.println(恭喜你,和渣男陈汉升约会吧);    }}

Annotationdemo测试代码

public class AnnotationDemo {    @Test    public void testBookStore() throws Exception {       ///分析类注释        Class c = BookStore.class;        if (c.isAnnotationPresent(Book.class)) {            Book book = (Book) c.getDeclaredAnnotation(Book.class);            System.out.println(book.value());            System.out.println(book.price());            System.out.println(Arrays.toString(book.authors()));        }        //解析方法上的注释        Method m = c.getDeclaredMethod("buyBook");        if (m.isAnnotationPresent(Book.class)) {            Book book = m.getDeclaredAnnotation(Book.class);            System.out.println(book.value());            System.out.println(book.price());            System.out.println(Arrays.toString(book.authors()));        }    }}
模拟Junit框架

需求:定义几种方法,只要添加Mytest注释,启动时就可以触发执行

步骤分析

  • ①定义自定义注解Mytest,只能注解方法,生存范围一直在
  • 定义几种方法,只要有@Mytest注释法,启动时就可以触发执行,没有这种注释法就不能执行

因为我们没有模拟运行键,所以我们用main模拟

代码展示

Mytest注解代码代码

@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.METHOD)public @interface MyTest {}

测试代码

 

public class Test {    @MyTest    public void test(){        System.out.println("====test=====");    }    public void test1(){        System.out.println(===test1=======));    }    public void test2(){        System.out.println(===test2=======));    }    @MyTest    public static void main(String[] args) throws Exception {        Test test=new Test();        Class c= Test.class;        Method[] methods=c.getDeclaredMethods();        for (Method method : methods) {            if (method.isAnnotationPresent(MyTest.class)) {                method.invoke(test);            }        }    }}

上一篇 Java Long对象对比,用equals函数
下一篇 idea写springboot,配置kafka版本的问题

文章素材均来源于网络,如有侵权,请联系管理员删除。