Java 注解

一、概念和基本注解

    从JDK1.5开始,引入了源代码中的注解这一机制。注解使得 Java 源代码中不但可以包含功能性的实现代码,还可以包含元数据。

    那么什么是元数据呢?所谓元数据,就是描述数据的数据。比如说一张图片,图片内容是它的主体数据,那么像图片的创建时间、修改时间、创建者等等这些数据,就是这张图片的元数据。

    那么元数据有什么用呢?我们可以用元数据来创建文档、跟踪代码的依赖性和执行编译时的格式检查,并可以代替系统中原有的配置文件。

    Java 注解是 Java 代码里的特殊标记,为我们在代码中添加用 Java 程序无法表达的额外信息提供了一种格式化方法,使我们可以在编译、类加载、运行时使用这些被注解修饰的程序元素(这些程序元素包括:类、属性、方法等)。

    使用注解时要在其前面加上一个 “@” 符号,表明后面的内容为注解。

    在 Java 的 java.lang 包中,预定义了三个注解,它们分别是限定重写父类方法的@Override、标记已过时的@Deprecated和抑制编译器警告的@SuppressWarnings,通常称这三个注解为内建注解或基本注解。

    @Override 在我们编程过程中经常遇到,就不细讲了;@Deprecated 表示该类成员已经过时,在未来的版本中可能会被删除,不建议使用。@SuppressWarnings 和前两个注解有些不同,这个注解带有一个属性,表示要抑制什么样的警告信息,相关属性值的含义如下:

@SuppressWarnings(value = "deprecation") //使用了过时的程序元素
@SuppressWarnings(value = "unchecked") //执行了未检查的转换
@SuppressWarnings(value = "unused") //有程序元素未被使用
@SuppressWarnings(value = "fallthrough") //switch 程序块直接通往下一种情况,而没有break
@SuppressWarnings(value = "path") //在类路径中有不存在的路径
@SuppressWarnings(value = "serial") //在可序列化的类上缺少 serialVersionUID 定义
@SuppressWarnings(value = "finally") //任何 finally 子句不能正常完成
@SuppressWarnings(value = "all") //所有情况

二、自定义注解

    注解之所以强大,能被众多框架所使用的主要原因在于,它可以允许程序员自定义注解,使 Java 程序变成自描述的。注解的语法形式和接口差不多,只不过在 interface 前面多了一个 @ 符号。

    我们可以在自定义注解时定义属性,在注解类型的定义中以无参方法的形式来声明,其方法名和返回值分别定义了该属性的名字和类型。另外需要注意的是,使用带属性的注解时,需要给属性赋值,不过可以在定义注解时,给属性赋默认值。

    Java中注解成员的类型必须是如下几类: 

1. 基本数据类型(boolean, byte, char, short, int, long, float, double); 2. String; 3. Class; 4. 枚举; 5. 其他的注解; 6. 以上类型的数组;

public @interface MyAnnotation {
      String name() default "张三";
      int age() default 22;
}

三、元注解

    上面提到了元数据——描述数据的数据。还有一个元注解的概念,即描述注解的注解——使用不同注解对注解进行注解。Java 为注解单独提供了四种元注解,即@Target、@Retention、@Documented和@Inherited。下面将分别介绍这四种元注解。

    1、@Target

    使用 @Target 注解的目的是用于指定被修饰的注解能用于修饰哪些程序元素。如果注解定义中不存在 @Target 元注解,则此注解可以用于任意程序元素上,如果存在这样的元注解,则编译器强制实施指定的使用规则。

/**
 * ElementType.ANNOTATION_TYPE : 限制此注解用于注解类
 * ElementType.CONSTRUCTOR : 限制此注解用于构造方法
 * ElementType.FIELD : 限制此注解用于字段属性(包括枚举变量)
 * ElementType.LOCAL_VARIABLE : 限制此注解用于局部变量声明
 * ElementType.METHOD : 限制此注解用于方法声明
 * ElementType.PACKAGE : 限制此注解用于包声明
 * ElementType.PARAMETER : 限制此注解用于参数声明
 * ElementType.TYPE : 限制此注解用于类、接口(包括注解类型)或枚举声明
 */
@Target({ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.LOCAL_VARIABLE,
        ElementType.METHOD, ElementType.PACKAGE, ElementType.PARAMETER, ElementType.TYPE})
public @interface MyAnnotation {

}

    2、@Retention

    @Retention 用于指定被修饰的注解的生命周期,生命周期分为三种,分别是 RetentionPolicy.CLASS、RetentionPolicy.RUNTIME 和 RetentionPolicy.SOURCE。如果注解定义中不存在 @Retention 元注解,则生命周期默认为 RetentionPolicy.CLASS。

/**
 * RetentionPolicy.CLASS : 编译器将把注解记录在 class 文件中,当运行 Java 程序时,虚拟机不再保留注解。
 * RetentionPolicy.RUNTIME : 编译器将把注解记录在 class 文件中,当运行 Java 程序时,虚拟机保留注解,程序可以通过反射获得该注解。
 * RetentionPolicy.SOURCE : 编译器将直接丢弃被修饰的注解
 */
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
      String name() default "张三";
      int age() default 22;
}
public class TestMyAnnotation {

    public static void main(String[] args) throws NoSuchMethodException, ClassNotFoundException {
        TestMyAnnotation testMyAnnotation = new TestMyAnnotation();
        testMyAnnotation.getObjectInfo();
    }

    @MyAnnotation
    @Deprecated
    public void getObjectInfo() throws ClassNotFoundException, NoSuchMethodException {
        Annotation[] annotations = Class.forName("annotation.TestMyAnnotation").getMethod("getObjectInfo").getAnnotations();
        for (Annotation annotation : annotations) {
            System.out.println("该注解是" + annotation);
            if (annotation instanceof MyAnnotation) {
                MyAnnotation myAnnotation = (MyAnnotation) annotation;
                System.out.println(myAnnotation.name());
                System.out.println(myAnnotation.age());
            }
        }
    }
    
}

    3、@Documented

    在默认的情况下,使用 javadoc 工具自动生成文档时,注解将被忽略掉。如果想在文档中也包含注解,必须使用 @Documented 注解。

@Documented
public @interface MyAnnotation {
}

    4、@Inherited

    默认情况下,父类的注解不被子类继承,如果要想继承父类注解,就必须使用  @Inherited 注解。

@Inherited
public @interface MyAnnotation {
}

四、总结

    其实,Java 注解可以简单理解成一种标记符号、描述信息。强大的并不是注解本身,而是对注解的灵活使用。以 Spring 常见的  @Component 注解为例。Spring 在启动时,上下文利用反射找到包路径下带有 @Component 的类,然后把它装载成 Spring 的 Bean。

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

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏专注 Java 基础分享

使用Java注解来简化你的代码

     注解(Annotation)就是一种标签,可以插入到源代码中,我们的编译器可以对他们进行逻辑判断,或者我们可以自己写一个工具方法来读取我们源代码中的注...

35950
来自专栏Java技术分享

怎样理解 java 注解和运用注解编程?

完整源码下载地址 GitHub - MatrixSeven/JavaAOP: 一个基于原生JDK动态代理实现的AOP小例子 使用反射结合JDK动态代理实现了类似...

41490
来自专栏JavaEdge

解惑Java注解类型(待更新)理解Java注解基本语法注解与反射机制运行时注解处理器Java 8中注解增强

java注解是在JDK5时引入的新特性,鉴于目前大部分框架(如Spring)都使用了注解简化代码并提高编码的效率,因此掌握并深入理解注解对于一个Java工程师是...

69110
来自专栏闻道于事

Java I/O流输入输出,序列化,NIO,NIO.2

29930
来自专栏用户2442861的专栏

JAVA注解

      http://blog.csdn.net/rj042/article/details/6399965

25420
来自专栏一个会写诗的程序员的博客

第12章 元编程与注解、反射第12章 元编程与注解、反射

反射(Reflection)是在运行时获取类的函数(方法)、属性、父类、接口、注解元数据、泛型信息等类的内部信息的机制。这些信息我们称之为 RTTI(Run-T...

10520
来自专栏社区的朋友们

Unity GC 优化 贴士大全

Unity中频繁的垃圾回收往往是造成手游性能瓶颈的一大元凶,本文对常见的造成频繁垃圾回收的原因做一个扫描,让开发者在日常开发中可以有意识的避开这些问题。

60400
来自专栏web编程技术分享

你可曾见过如此简单粗暴的JavaScript解说 -- if 判断的正确打开方式?

29650
来自专栏熊二哥

Java核心编程快速入门

Java核心编程部分的基础学习内容就不一一介绍了,本文的重点是JAVA中相对复杂的一些概念,主体内容如下图所示。 ? ? 反射reflect是理解Java语言...

23190
来自专栏张善友的专栏

在Entity Framework 中执行T-sql语句

从Entity Framework  4开始在ObjectContext对象上提供了2个方法可以直接执行SQL语句:ExecuteStoreQuery<T> 和...

233100

扫码关注云+社区

领取腾讯云代金券