Java学习笔记 16、注解

简介: Java学习笔记 16、注解

一、认识注解


1.1、介绍注解


注解(Annotation):从JDK5.0开始,Java增加了对元数据(MetaData)的支持,及注解。


Annotation就是代码中的特殊标记,这些标记可以通过设置在编译时、类加载时、运行时读取来执行相应的处理。通过注解可以在不改变原有逻辑的情况下,在源文件中嵌入一些补充信息。并且代码分析工具、开发工具和部署工具都可以通过这些补充信息进行验证部署。


Annoation可以像修饰符一样使用,可用于修饰包、类、构造器、方法…之前,并且能够设置指定的值保存在Annoation中的属性里,例如name=value。

目的:在JavaSE中,注解的使用目的例如标记过时的功能(@Deprecated), 忽略警告(@SuppressWarnings;在JavaEE/Android开发中注解占据了更重要的角色,例如Spring框架中的AOP通过注解来配置任意方法的切面,使用注解来代替JavaEE旧版中的繁冗代码与XML配置。


未来的开发模式都是基于注解的,例如:Spring2.5以上都是基于注解,JPA,Hibernate3.X,Struts2。

框架=注解+反射+设计模式


1.2、开发中常见注解使用


使用注解前需要在前面加上@符号,可以将其当做一个修饰符来使用。


1、用于生成文档的相关注解


一般使用于注释中,用于在使用javadoc工具来生成文档


类注释中:

@author:标明开发该类模块的作者,多个作者之间可使用,分割。

@version:标明该类模块的版本。

@since:从哪个版本开始增加的,我们常看到源代码注释中会标注。

@see:参考转向,也就是相关主题。

一般用于方法中:

@param:用于在方法注释中,对方法中某参数的说明,如果没有参数就不能写。

@return:用于在方法注释中,对方法返回值的说明,如果方法的返回值类型是void就不能写。

@exception:对方法可能抛出的异常进行说明 ,如果方法没有用throws显式抛出的异常就不能写 其中


2、在编译时进行格式检查(JDK内置的三个基本注解)


一般修饰在方法:


@Override: 限定重写父类方法, 该注解只能用于方法,可以来检查是否为重写的方法。

@Deprecated: 用于表示所修饰的元素(类, 方法等)已过时。通常是因为所修饰的结构危险或存在更好的选择。

@SuppressWarnings: 抑制编译器警告。


3、跟踪代码依赖性,实现替代配置文件功能


①Servlet3.0中提供的注解,使得不再需要在web.xml中进行Servlet的部署访问。


[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YlCwnrSA-1613984978679)(https://gitee.com/changluJava/picture-bed/raw/master/mouse/20210221231848.png)]


通过使用@WebServlet("/login")来代替掉下面的配置文件(减少xml配置)。

②Spring中事务的配置,只用一个注解来替换掉了配置文件




二、自定义注解


2.1、自定义注解说明


对于自定义注解的说明:


定义Annotation时需要使用@interface关键字。

自定义注解自动继承了java.lang.annotation.Annotation接口,包含四个方法equals()、hashCode()、toString()、annotationType()。

Annoation中的成员变量以无参数方法的形式来声明。

其方法名和返回值定义了该成员的名字和类型,称之为配置参数。其类型只能是8种基本数据类型、String类型、Class类型、enum类型、Annotation类型以及上面所有类型的数组。

可以在定义成员变量时指定参数值,可在成员变量后使用default 默认值来进行初始化。

若是Annoation中只有一个参数成员,建议使用参数名为value。

使用说明:若是使用的注解中含有配置参数(即成员变量),那么使用时需要在()中指定参数值(对于有默认值的可以不写因为会自动赋值),例如:@注解(参数=值);若是Annotation中只有一个成员那么我们在使用时可以省略参数=,例如:@注解(值)。


注意:没有成员定义的Annotation称为标记;包含成员变量的Annotation称为元数据。


自定义注解


public @interface MyAnnotation {
    String value() default "changlu";
}
@MyAnnotation(value = "changlu")  //或 @MyAnnotation("liner")   或  @MyAnnotation() 
class Person{
}


@MyAnnotation(value = "changlu")与@MyAnnotation("liner")都相当于对其中的value重新赋值了,由于注解中只有一个成员所以可以省略参数直接填值。

@MyAnnotation() :会默认使用注解成员中的值。


2.2、JDK1.5提供的四个元注解


四个标准的元注解:Retention、Target、Documented、Inherited


@Retention


@Retention:用来指定该Annotation的生命周期。


@Documented
@Retention(RetentionPolicy.RUNTIME)  //生命周期为运行时
@Target(ElementType.ANNOTATION_TYPE) //只可标注在注解类型上
public @interface Retention {
    /**
     * Returns the retention policy.
     * @return the retention policy
     */
    RetentionPolicy value();
}
//@Retention的成员返回值RetentionPolicy,一个枚举类
public enum RetentionPolicy {
    SOURCE,//在源文件中有效(仅在源文件中保留),编译器编译时会忽略该注解
    CLASS,//仅在class文件中有效(即class保留),当运行Java程序时,JVM不会保留注解。
    RUNTIME//:在运行时有效(即运行时保留),当运行 Java 程序时, JVM 会保留注释。程序可以通过反射获取该注释。
}


[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zmdpvsuI-1613984978684)(https://gitee.com/changluJava/picture-bed/raw/master/mouse/20210222151009.png)]


该注解使用不同RetentionPolicy的枚举实例表示的不同生命周期


@Target


@Target:用于指定被修饰的Annotation能用于修饰哪些程序元素(如方法、类、包、参数…)。


@Documented
@Retention(RetentionPolicy.RUNTIME) //生命周期为运行时
@Target(ElementType.ANNOTATION_TYPE)//只可标注在注解类型上
public @interface Target {
    //是一个数组枚举类
    ElementType[] value();
}
//@Target的成员返回值是一个注解
public enum ElementType {
    TYPE,//使用于描述类、接口(包括注解类型)或enum声明
    FIELD,//使用于属性(包含注解内容)
    METHOD,//使用于方法
    PARAMETER,//参数
    CONSTRUCTOR,//用于描述构造器
    LOCAL_VARIABLE,//描述局部变量
    ANNOTATION_TYPE,//描述注解类型声明
    PACKAGE,//包
    TYPE_PARAMETER,//jdk1.8新增,表示该注解能写在类型变量的声明语句中(如:泛型声明)
    TYPE_USE//jdk1.8新增,表示该注解能写在使用类型的任何语句中
}


@Tatget({ElementType.TYPE_USE}):即可在任何语句中添加注解。


@Documented


@Documented: 用于指定被 修饰的 Annotation 类能够被 javadoc工具提取成文档。默认情况下,javadoc是不包括注解的。


若定义了@Documented的注解务必设置@Retention的值为Runtime(生命周期为运行时)。
@Documented
@Retention(RetentionPolicy.RUNTIME) //生命周期是运行时
@Target(ElementType.ANNOTATION_TYPE) //只可标注在注解类型上
public @interface Documented {
}



@Inherited


@Inherited:被其修饰的注解具有继承性,若某个类使用了被@Inherited修饰的注解,则其子类将自动具有该注解。


实际使用较少。


@Documented
@Retention(RetentionPolicy.RUNTIME)//生命周期是运行时
@Target(ElementType.ANNOTATION_TYPE)//只可标注在注解类型上
public @interface Inherited {
}



三、利用反射获取注解信息


自定义注解:


@Documented
@Target({ElementType.ANNOTATION_TYPE,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)//运行时
@Inherited
public @interface MyAnnotation {
    String value() default "changlu";
}


通过反射获取到类的注解以及注解值:


@MyAnnotation("clle")
class Person{
}
class Student extends Person{
}
public class Test {
    public static void main(String[] args) {
        Class<Person> clazz = Person.class;
        //获取该类上指定的注解类型
        MyAnnotation anno = clazz.getAnnotation(MyAnnotation.class);
        System.out.println(anno.value());//clle
        //查看Student是否继承了Person的注解
        Annotation[] annotations = Student.class.getAnnotations();
        for (Annotation annotation : annotations) {
            System.out.println(annotation);//@xyz.changlu.MyAnnotation(value=clle)
        }
    }
}



认识一下AnnotatedElement接口


Class实现了该接口,才会有获取注解的相关方法:


[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-h8XjEarH-1613984978686)(https://gitee.com/changluJava/picture-bed/raw/master/mouse/20210222155559.png)]


isAnnotationPresent():此元素上是否存在指定注解类型,若存在返回true,不存在返回false。

getAnnotation():获取该元素上指定注解类型的实例。

getAnnotations():获取该元素上的所有注解实例。

getAnnotationsByType:获取该元素上指定注解类的所有实例。

Class类的继承图:


[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9ZaYFZCA-1613984978690)(https://gitee.com/changluJava/picture-bed/raw/master/mouse/20210222160004.png)]



四、JDK8中注解的新特性


4.1、可重复注解(两种方式)


两种方式实现

什么是可重复注解呢?就是在同一个部分上定义两个或多个相同的注解,其中的值可不一样。


①jdk1.8之前,需要通过再定义一个注解,其中包含我们想要使用的注解数组


@Target({ElementType.ANNOTATION_TYPE,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)//运行时
@Inherited
public @interface MyAnnotation {
    String value() default "changlu";
}
//该注解中我们定义@MyAnnotation数组
@Target({ElementType.ANNOTATION_TYPE,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)//运行时
@Inherited
@interface MyAnnotations{
    //定义注解数组
    MyAnnotation[] value();
}


@MyAnnotations({@MyAnnotation("changlu"),@MyAnnotation("liner")})
class Person{
}


我们通过定义@MyAnnotations注解的成员为注解数组形式来实现可重复注解。


②jdk1.8新增@Repeatable注解


@Target({ElementType.ANNOTATION_TYPE,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Repeatable(MyAnnotations.class)//注意:这里新增使用@Repeatable()其中值为一个Class类就是下面定义的MyAnnotations
public @interface MyAnnotation {
    String value() default "changlu";
}
@Target({ElementType.ANNOTATION_TYPE,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)//运行时
@Inherited
@interface MyAnnotations{
    //定义注解数组
    MyAnnotation[] value();
}


在@MyAnnotation中使用了@Repeatable(MyAnnotations.class)注解,其中定义了指定一个容器注解。


@MyAnnotation("changlu")
@MyAnnotation("liner")
class Person{
}


这样我们就能够直接在一个类上定义多个相同注解了,相较于第一种方式需要先声明@MyAnnotations,其中再包裹两个注解。


我们再看一下@Repeatable注解:


@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Repeatable {
    Class<? extends Annotation> value();//其中成员的返回值为一个Class类型
}


获取可重复注解的值(两种方式)

获取上面使用@Repeatable注解方法的设置的重复注解:


@MyAnnotation("changlu")
@MyAnnotation("liner")
class Person{
}


public class AnnotationTest {
    public static void main(String[] args) {
        //方式一:通过getAnnotation()获取MyAnnotations容器注解的实例,接着遍历
        MyAnnotations annotation = Person.class.getAnnotation(MyAnnotations.class);
        MyAnnotation[] value = annotation.value();
        for (MyAnnotation myAnnotation : value) {
            System.out.println(myAnnotation.value());
        }
        //changlu
        //liner
    }
    //方式二:通过使用getAnnotationsByType()获取MyAnnotation注解数组,接着重复遍历即可
    @Test
    public void test(){
        MyAnnotation[] annos = Person.class.getAnnotationsByType(MyAnnotation.class);
        for (MyAnnotation anno : annos) {
            System.out.println(anno.value());
        }
        //changlu
        //liner
    }
}


通过查阅博客得知使用新增的@Repeatable,在编译器编译时实际上也是转换为使用的MyAnnotations注解表示。


@MyAnnotation("changlu")
@MyAnnotation("liner")      
  转换后
@MyAnnotations(value=[@MyAnnotation("changlu"),@MyAnnotation("liner")])
//并且在字节码中数组使用[]来表示


对于获取单个注解值使用getAnnotation()方法,获取重复注解使用getAnnotationsByType()。


详细内容可看我下面的参考文章[1]。



4.2、新增类型注解(2个)


也就是在@Target注解中的成员参数ElementType枚举类中添加了两个实例:



ElementType.TYPE_PARAMETER :表示该注解能写在类型变量的声明语 句中(如:泛型声明)。

ElementType.TYPE_USE:表示该注解能写在使用类型的任何语句中。

区别说明:在Java 8之前,注解只能是在声明的地方所使用,Java8开始,注解可以应用在任何地方(可直接使用ElementType.TYPE_USE)。



相关文章
|
14天前
|
XML Java 编译器
Java注解的底层源码剖析与技术认识
Java注解(Annotation)是Java 5引入的一种新特性,它提供了一种在代码中添加元数据(Metadata)的方式。注解本身并不是代码的一部分,它们不会直接影响代码的执行,但可以在编译、类加载和运行时被读取和处理。注解为开发者提供了一种以非侵入性的方式为代码提供额外信息的手段,这些信息可以用于生成文档、编译时检查、运行时处理等。
50 7
|
2月前
|
XML Java 编译器
Java学习十六—掌握注解:让编程更简单
Java 注解(Annotation)是一种特殊的语法结构,可以在代码中嵌入元数据。它们不直接影响代码的运行,但可以通过工具和框架提供额外的信息,帮助在编译、部署或运行时进行处理。
97 43
Java学习十六—掌握注解:让编程更简单
|
20天前
|
Java 编译器 数据库
Java 中的注解(Annotations):代码中的 “元数据” 魔法
Java注解是代码中的“元数据”标签,不直接参与业务逻辑,但在编译或运行时提供重要信息。本文介绍了注解的基础语法、内置注解的应用场景,以及如何自定义注解和结合AOP技术实现方法执行日志记录,展示了注解在提升代码质量、简化开发流程和增强程序功能方面的强大作用。
55 5
|
1月前
|
Java 开发者 Spring
[Java]自定义注解
本文介绍了Java中的四个元注解(@Target、@Retention、@Documented、@Inherited)及其使用方法,并详细讲解了自定义注解的定义和使用细节。文章还提到了Spring框架中的@AliasFor注解,通过示例帮助读者更好地理解和应用这些注解。文中强调了注解的生命周期、继承性和文档化特性,适合初学者和进阶开发者参考。
56 14
|
1月前
|
前端开发 Java
[Java]讲解@CallerSensitive注解
本文介绍了 `@CallerSensitive` 注解及其作用,通过 `Reflection.getCallerClass()` 方法返回调用方的 Class 对象。文章还详细解释了如何通过配置 VM Options 使自定义类被启动类加载器加载,以识别该注解。涉及的 VM Options 包括 `-Xbootclasspath`、`-Xbootclasspath/a` 和 `-Xbootclasspath/p`。最后,推荐了几篇关于 ClassLoader 的详细文章,供读者进一步学习。
36 12
|
1月前
|
Java 数据库连接 API
Spring 框架的介绍(Java EE 学习笔记02)
Spring是一个由Rod Johnson开发的轻量级Java SE/EE一站式开源框架,旨在解决Java EE应用中的多种问题。它采用非侵入式设计,通过IoC和AOP技术简化了Java应用的开发流程,降低了组件间的耦合度,支持事务管理和多种框架的无缝集成,极大提升了开发效率和代码质量。Spring 5引入了响应式编程等新特性,进一步增强了框架的功能性和灵活性。
46 0
|
1月前
|
Java 编译器
Java进阶之标准注解
Java进阶之标准注解
32 0
|
2月前
|
JSON Java 数据库
java 常用注解大全、注解笔记
关于Java常用注解的大全和笔记,涵盖了实体类、JSON处理、HTTP请求映射等多个方面的注解使用。
43 0
java 常用注解大全、注解笔记
|
2月前
|
IDE Java 编译器
java的反射与注解
java的反射与注解
17 0
|
3月前
|
Java 编译器 程序员
Java注解,元注解,自定义注解的使用
本文讲解了Java中注解的概念和作用,包括基本注解的用法(@Override, @Deprecated, @SuppressWarnings, @SafeVarargs, @FunctionalInterface),Java提供的元注解(@Retention, @Target, @Documented, @Inherited),以及如何自定义注解并通过反射获取注解信息。
Java注解,元注解,自定义注解的使用
下一篇
DataWorks