​Java 注解详解

简介

注解是在Java 1.5之后引入的,为的是可以直接在代码中编写元信息。在注解发布之前,如果想要描述代码只能将其写入到其他文件中,例如xml。 注解可以应用于包,类,方法,字段,参数,类型(Java 8之后)。注解并不会直接影响代码,它只是为第三方系统提供代码的元信息,第三方系统通过解析这些注解获取信息,从而执行不同的方法。

注解的语法

注解使用@开头,例如

@Annotation
public void annotatedMethod(){
}

注解同样也可以有参数

@Annotation(
   info = "I am an annotation",
   counter = "55"
)
public void annotatedMehod() {
...
 }

如果只有一个参数,参数名可以省略

@Annotation("I am an annotation")
public void annotatedMehod() {
...
 }

多个注解可以同时修饰同一个元素

@Annotation (info = "UauO")
@Annotation2
class AnnotatedClass { ... }
用途

注解有多种用途,最常用的几种方式是:

  • 提供信息给编译器: 编译器可以分析注解,获取不同的规则产生警告甚至错误。例如Java 8的 @FunctionInterface 注解,如果这个注解修饰的接口包含了2个及以上的方法编译器就会发出错误警告
  • 生成文档: 一些特殊的注解处理其可以通过解析特定注解生成文档,例如Jenkins等
  • 代码生成: 通过注解提供的信息,自动生成代码,例如JAXB
  • 运行时处理: 在运行时分析注解,例如Spring,JPA等
内置注解

Java内置了一些常用的注解,例如下面要介绍的元注解,之所以叫元注解是因为它们是修饰注解的注解

  • @Retention 表示注解的声明周期,可选值为:
    • SOURCE: 仅存在于源码中,被编译器和JVM忽略
    • CLASS: 保存在字节码中,编译器可以获取,JVM忽略
    • RUNTIME: 运行时可以获取,整个生命周期都可以获取
  • @Target 表示注解可以修饰那些元素
    • ANNOTATION_TYPE: 可以修饰注解
    • CONSTRUCTOR: 可以修饰构造函数
    • FIELD: 可以修饰字段
    • LOCAL_VARIABLE: 可以修饰本地变量
    • METHOD: 可以修饰方法
    • PACKAGE: 可以修饰包
    • PARAMETER: 可以修饰方法参数
    • TYPE: 可以修饰类
  • @Documented: 可以由Javadoc 工具生成文档
  • @Inherited: 默认注解是不能被子类继承的,这个注解修饰后注解可以被所有子类继承。
  • @Deprecated: 表示被修饰的元素已经被遗弃了,以后不再维护。
  • @SuppressWarning: 通知编译器不要为被修饰的元素产生错误
  • @Override: 子类重写父类方法。
  • @SafeVarargs: 方法或者构造函数的可变参数不会执行不安全的操作,具体可参考@SafeVarargs
  • @Repeatable: Java 8提供注解,表示注解可以重复 例如,没有这个注解的之后,同一个注解在同一个元素上使用一次,所以如果包含了多个值需要使用数组的形式 @Retention( RetentionPolicy.RUNTIME ) @Target( ElementType.TYPE_USE ) public @interface RepeatedValues { CanBeRepeated[] value(); } 有了@Repeatable之后可以直接定义这个注解是可以重复使用的 @Retention( RetentionPolicy.RUNTIME ) @Target( ElementType.TYPE_USE ) @Repeatable( RepeatedValues.class ) public @interface CanBeRepeated { String value(); } @CanBeRepeated( "the color is green" ) @CanBeRepeated( "the color is red" ) @CanBeRepeated( "the color is blue" ) public class RepeatableAnnotated { }
  • @FunctionInterface: 修饰接口表示其是一个函数式接口,只能包含一个函数声明。
自定义注解

自定义注解的关键字是@interface 例如:

@Retention( RetentionPolicy.RUNTIME )
@Target( ElementType.TYPE )
public @interface CustomAnnotationClass
{

    public String author() default "danibuiza";

    public String date();

}

上述定义了一个注解CunstomAnnotationClass,它由两个参数author和date,author的默认值是 ‘danibuiza’,这个注解可以修饰类,且在运行时可见。 使用注解

@CustomAnnotationClass( date = "2014-05-05" )
public class AnnotatedClass
{ 
...
}

java.lang.Class,java.lang.reflect.Method,java.lang.reflect.Field等都实现了getAnnotations(),isANnotationPresent(Annotation),getAnnotation(class)这些方法,这些方法是使用自定义注解的主要方法,例如:

public static void main( String[] args ) throws Exception
{

    Class<AnnotatedClass> object = AnnotatedClass.class;
    // Retrieve all annotations from the class
    Annotation[] annotations = object.getAnnotations();
    for( Annotation annotation : annotations )
    {
        System.out.println( annotation );
    }

    // Checks if an annotation is present
    if( object.isAnnotationPresent( CustomAnnotationClass.class ) )
    {

        // Gets the desired annotation
        Annotation annotation = object.getAnnotation( CustomAnnotationClass.class );

        System.out.println( annotation );

    }
    // the same for all methods of the class
    for( Method method : object.getDeclaredMethods() )
    {

        if( method.isAnnotationPresent( CustomAnnotationMethod.class ) )
        {

            Annotation annotation = method.getAnnotation( CustomAnnotationMethod.class );

            System.out.println( annotation );

        }

    }
}

运行后输出如下:

@com.danibuiza.javacodegeeks.customannotations.CustomAnnotationClass(getInfo=Info, author=danibuiza, date=2014-05-05)

@com.danibuiza.javacodegeeks.customannotations.CustomAnnotationClass(getInfo=Info, author=danibuiza, date=2014-05-05)

@com.danibuiza.javacodegeeks.customannotations.CustomAnnotationMethod(author=friend of mine, date=2014-06-05, description=annotated method)
@com.danibuiza.javacodegeeks.customannotations.CustomAnnotationMethod(author=danibuiza, date=2014-06-05, description=annotated method)
关于注解的继承问题

如果使用@Inherited修饰注解,那么子类是可以继承父类的注解的,但是这仅仅对于继承类的时候才有用,如果是实现接口,那么继承不再有效,例如:

@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface InheritedAnnotation
{
}

@InheritedAnnotation 
public class AnnotatedSuperClass
{
    public void oneMethod()
    {
    }
}

public class AnnotatedSubClass extends AnnotatedSuperClass
{
    @Override
    public void oneMethod(){
    }
}

System.out.println( "is true: " + AnnotatedSuperClass.class.isAnnotationPresent( InheritedAnnotation.class ) );

System.out.println( "is true: " + AnnotatedSubClass.class.isAnnotationPresent( InheritedAnnotation.class ) );

输出:

is true: true
is true: true

而对于实现接口:

@InheritedAnnotation
public interface AnnotatedInterface
{
    public void oneMethod();
}

public class AnnotatedImplementedClass implements AnnotatedInterface
{
    @Override
    public void oneMethod()
    {
    }
}

System.out.println( "is true: " + AnnotatedInterface.class.isAnnotationPresent( InheritedAnnotation.class ) );

System.out.println( "is true: " + AnnotatedImplementedClass.class.isAnnotationPresent( InheritedAnnotation.class ) );

输出如下:

is true: true
is true: false

原文发布于微信公众号 - 代码拾遗(gh_8f61e8bcb1b1)

原文发表时间:2018-05-16

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏10km的专栏

fastjson:实现对java.nio.ByteBuffer数据类型的支持

一般情况下,我们都用byte[]作为保存二进制数据的数据类型,较少用ByteBuffer来表示字节数组。然而最近的工作中需要二进制数据(字节数组)即支持fast...

34480
来自专栏Java后端技术

Java自定义注解开发

  最近在自己搞一个项目时,遇到可需要开发自定义注解的需求,对于没有怎么关注这些java新特性的来说,比较尴尬,索性就拿出一些时间,来进行研究下自定义注解开发的...

54730
来自专栏物联网事

Java 注解

java.lang.annotation.RetentionPolicy.java

473120
来自专栏Android先生

Android-Annotation教你写自定义注解

地址:https://juejin.im/post/5a14158df265da432c237bfc

12720
来自专栏码匠的流水账

聊聊flink的SourceFunction

flink-streaming-java_2.11-1.6.2-sources.jar!/org/apache/flink/streaming/api/func...

32130
来自专栏小樱的经验随笔

BZOJ 2456: mode(新生必做的水题)

2456: mode Time Limit: 1 Sec  Memory Limit: 1 MB Submit: 4868  Solved: 2039 Des...

28060
来自专栏史上最简单的Spring Cloud教程

Java注解详解

在使用SpringBoot作为Web敏捷开发的框架之后,SpringBoot除了自动装配配置的便捷之外,在很多时候需要基于注解来开发。注解不仅增加了代码的可读性...

33470
来自专栏小樱的经验随笔

Code forces 719A Vitya in the Countryside

A. Vitya in the Countryside time limit per test:1 second memory limit per test:2...

37060
来自专栏码匠的流水账

聊聊rocketmq的NettyEncoder及NettyDecoder

本文主要研究一下rocketmq的NettyEncoder及NettyDecoder

19410
来自专栏Android知识点总结

TIII-Android技术篇之注解Annotation

9020

扫码关注云+社区

领取腾讯云代金券