`
longgangbai
  • 浏览: 7352085 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

注解你真的深入了解了吗?(4)

阅读更多

对注释的注释


结束关于注释的讨论之前(至少在本系列文章中),我想简要地讨论一下注释的注释。第 1 部分中所接触的预定义注释类型都有预定义的目的。但是在编写自己的注释类型时,注释类型的目的并不总是显而易见的。除了基本的文档外,可能还要针对某个特定的成员类型或者一组成员类型编写类型。这就要求您为注释类型提供某种元数据,以便编译器保证按照预期的目的使用注释。

当然,首先想到的就是 Java 语言选择的元数据形式 —— 注释。您可以使用 4 种预定义的注释类型(称为 元注释)对您的注释进行注释。我将对这 4 种类型分别进行介绍。

指定目标


最明显的元注释就是允许何种程序元素具有定义的注释类型。毫不奇怪,这种元注释被称为 Target 。但是在了解如何使用 Target 之前,您还需要认识另一个类,该类被称为 ElementType ,它实际上是一个枚举。这个枚举定义了注释类型可应用的不同程序元素。清单 9 给出了完整的 ElementType 枚举:
清单 9. ElementType 枚举

package java.lang.annotation;
public enum ElementType {
  TYPE,			// Class, interface, or enum (but not annotation)
  FIELD,		// Field (including enumerated values)
  METHOD,		// Method (does not include constructors)
  PARAMETER,		// Method parameter
  CONSTRUCTOR,		// Constructor
  LOCAL_VARIABLE,	// Local variable or catch clause
  ANNOTATION_TYPE,	// Annotation Types (meta-annotations)
  PACKAGE		// Java package
}

清单 9 中的枚举值意义很明确,您自己可以分析其应用的目标(通过后面的注解)。使用 Target 元注释时,至少要提供这些枚举值中的一个并指出注释的注释可以应用的程序元素。清单 10 说明了 Target 的用法:

清单 10. 使用 Target 元注释

package com.oreilly.tiger.ch06;
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
/**
 * Annotation type to indicate a task still needs to be completed
 */
@Target({ElementType.TYPE,
         ElementType.METHOD,
         ElementType.CONSTRUCTOR,
         ElementType.ANNOTATION_TYPE})
public @interface TODO {
  String value();
}

现在,Java 编译器将把 TODO 应用于类型、方法、构造函数和其他注释类型。这样有助于避免他人误用您的注释类型(或者最好的地方是, 您自己也不会因为疲惫而误用它)。

设置保持性


下一个要用到的元注释是 Retention 。这个元注释和 Java 编译器处理注释的注释类型的方式有关。编译器有几种不同选择:

  • 将注释保留在编译后的类文件中,并在第一次加载类时读取它。
  • 将注释保留在编译后的类文件中,但是在运行时忽略它。
  • 按照规定使用注释,但是并不将它保留到编译后的类文件中。

这三种选项用 java.lang.annotation.RetentionPolicy 枚举表示,如清单 11 所示:

清单 11. RetentionPolicy 枚举

package java.lang.annotation;
public enum RetentionPolicy {
  SOURCE,		// Annotation is discarded by the compiler
  CLASS,		// Annotation is stored in the class file, but ignored by the VM
  RUNTIME		// Annotation is stored in the class file and read by the VM
}

现在可以看出, Retention 元注释类型使用清单 11 所示的枚举值中的一个作为惟一的参数。可以将该元注释用于您的注释,如清单 12 所示:

清单 12. 使用 Retention 元注释

@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {
  // annotation type body
}

如清单 12 所示,这里可以使用简写形式,因为 Retention 只有一个成员变量。如果要将保持性设为 RetentionPolicy.CLASS ,那么什么也不需要做,因为这就是默认行为。

添加公共文档


下一个元注释是 Documented 。这个元注释也非常容易理解,部分原因是 Documented 是一个标记注释。您应该还记得第 1 部分中曾经提到,标记注释没有成员变量。 Documented 表示注释应该出现在类的 Javadoc 中。在默认情况下,注释 包括在 Javadoc 中,如果花费大量时间注释一个类、详细说明未完成的工作、正确完成了什么或者描述行为,那么您应该记住这一点。

清单 13 说明了 Documented 元注释的用法:

清单 13. 使用 Documented 元注释

package com.oreilly.tiger.ch06;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
 * Marker annotation to indicate that a method or class
 *   is still in progress.
 */
        @Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface InProgress { }
      

Documented 的一个实用技巧是保持性策略。注意,清单 13 中规定注释的保持性(retention)是 RUNTIME ,这是使用 Documented 注释类型所 必需的。Javadoc 使用虚拟机从其类文件(而非源文件)中加载信息。确保 VM 从这些类文件中获得生成 Javadoc 所需信息的惟一方法是将保持性规定为 RetentionPolicy.RUNTIME 。这样,注释就会保留在编译后的类文件中 并且由虚拟机加载,然后 Javadoc 可以从中抽取出来添加到类的 HTML 文档中。

设置继承


最后一个元注释 Inherited ,可能是最复杂、使用最少、也最容易造成混淆的一个。这就是说,我们简单地看一看就可以了。

首先考虑这样一种情况:假设您通过定制的 InProgress 注释标记一个类正在开发之中,这完全没有问题,对吧?这些信息还会出现在 Javadoc 中,只要您正确地应用了 Documented 元注释。现在,假设您要编写一个新类,扩展那个还在开发之中的类,也不难,是不是?但是要记住,那个超类还在开发之中。如果您使用子类,或者查看它的文档,根本没有线索表明还有什么地方没有完成。您本来希望看到 InProgress 注释被带到子类中 —— 因为这是 继承 的 —— 但情况并非如此。您必须使用 Inherited 元注释说明所期望的行为,如清单 14 所示:

清单 14. 使用 Inherited 元注释

package com.oreilly.tiger.ch06;
import java.lang.annotation.Documented;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
 * Marker annotation to indicate that a method or class
 *   is still in progress.
 */
@Documented
        @Inherited
@Retention(RetentionPolicy.RUNTIME)
public @interface InProgress { }
      

添加 @Inherited 后,您将看到 InProgress 出现在注释类的子类中。当然,您并不希望所有的注释类型都具有这种行为(因此默认值是 继承的)。比如, TODO 注释就不会(也不应该)被传播。但是对于这里示范的情况, Inherited 可能非常有用。

 




回页首

 

结束语


现在,您也许已经准备回到 Java 世界为所有的事物编写文档和注释了。这不禁令我回想起人们了解 Javadoc 之后发生的事情。我们都陷入了文档过滥的泥潭,直到有人认识到最好使用 Javadoc 来理清容易混淆的类或者方法。无论用 Javadoc 做了多少文章,也没有人会去看那些易于理解的 getXXX()setXXX() 方法。

注释也可能出现同样的趋势,虽然不一定到那种程度。经常甚至频繁地使用标准注释类型是一种较好的做法。所有的 Java 5 编译器都支持它们,它们的行为也很容易理解。但是,如果要使用定制注释和元注释,那么就很难保证花费很大力气创建的那些类型在您的开发环境之外还有什么意义。因此要慎重。在合理的情况下使用注释,不要荒谬使用。无论如何,注释都是一种很好的工具,可以在开发过程中提供真正的帮助。

分享到:
评论

相关推荐

    java注解深入理解

    首先,我们需要了解注解的基本概念。Java注解是以`@`符号开头的特殊声明,后面跟着注解的名称。例如,`@Override`用于表明一个方法是重写父类的方法。Java标准库提供了许多内置注解,如`@Deprecated`(表示某个API已...

    Springmvc基础三深入理解注解

    本教程将深入探讨 Spring MVC 中的核心注解,帮助你更好地理解和运用它们。 1. **`@Controller` 注解**:这是 Spring MVC 中用于标记一个类作为处理 HTTP 请求的控制器的注解。当 Spring 容器扫描到带有此注解的类...

    Spring java注解,元注解和自定义注解

    在深入了解Spring框架中的注解应用之前,我们首先需要对Java注解有一个基本的认识。Java注解(Annotation)是一种元数据,可以为程序代码添加额外的信息。注解本身并不改变程序的行为,但它可以通过工具或编译器被...

    @SpringBootApplication注解到底做了什么,你真的了解吗?

    下面我们将深入探讨这些注解的作用及其背后的机制。 首先,`@SpringBootConfiguration`是`@Configuration`的扩展,用于标记一个类为配置类,这样Spring会将此类中的@Bean注解的方法当作Bean定义来处理,从而在容器...

    精读鸿蒙内核源码,百万汉字注解分析;百篇博客深入解剖.zip

    百篇博客深入解剖》是一份详尽的资料,旨在帮助开发者深入了解华为鸿蒙操作系统(HarmonyOS)的内核设计与实现。这份资源包含了对鸿蒙内核LiteOS A部分的深度解读,通过百万汉字的细致注解,使得原本复杂的源码变得...

    Java自定义注解使用反射获取字段注解

    本文将深入探讨如何通过反射机制来获取自定义注解以及其在字段上的应用。 首先,我们需要了解什么是自定义注解。自定义注解是以`@`开头,后跟自定义的名称。定义一个注解的基本结构如下: ```java import java....

    java 自定义注解验证

    Java 自定义注解验证是Java...本案例中的三个自定义注解可能是针对特定业务场景而设计的,通过阅读源代码,我们可以更深入地了解它们的用途和实现方式。如果你对此有进一步的兴趣,可以尝试打开源代码进行学习和实践。

    java注解jar包

    Java注解是Java编程语言中的一个重要特性,它允许在代码中添加元数据,这些元数据可以被编译器或运行时环境用来执行特定...通过深入理解和运用这些工具,开发者可以更好地利用注解带来的优势,提高开发效率和代码质量。

    注解,注解的示例以及解释说明,能让大家更好的了解注解的使用方式

    本篇文章将深入探讨注解的基本概念、种类、使用场景及其工作原理。 一、注解的基本概念 注解以`@`符号开头,后面跟着注解类型的名字。例如,`@Override`表示方法是重写父类的方法。注解可以应用于类、接口、方法、...

    spring4基于java注解事例

    在本教程中,我们将深入探讨如何使用Spring 4框架,特别是其基于Java注解的配置方式,来构建一个高效、可维护的系统。Spring 4是Java企业级应用开发的首选框架,它提供了广泛的功能,包括依赖注入、AOP(面向切面...

    自定义注解得使用,模拟spring通过注解方式创建bean实例

    本篇将深入探讨如何自定义注解并模拟Spring通过注解方式创建bean实例。 首先,了解注解(Annotation)在Java中的角色。注解是一种元数据,它提供了在源代码中添加信息的方式,这些信息可以被编译器或运行时环境读取...

    注解javademo演示

    Java注解,也被称为元数据,是Java编程语言中的一个重要特性,它允许程序员在源代码中插入一些附加信息。这些信息可以被编译器或...通过阅读给定的博客和分析压缩包中的示例,你可以更深入地了解Java注解的用法和实践。

    ssh注解开发案例

    通过分析这些文件,初学者可以深入理解SSH框架中注解的使用方式,掌握如何利用注解进行快速开发,减少XML配置工作,提高开发效率。同时,案例提供的完整代码可以帮助开发者更好地将理论知识应用到实践中。

    webservice Demo注解+jax-ws

    Web服务(Web Service)是一种基于网络的、分布式的模块化组件,它提供了标准的方法来使得不同的应用程序能够在不同的...通过阅读提供的文档和实践示例,你将能够深入理解Web服务的基本原理,并具备实际操作的能力。

    struts2注解登陆

    首先,让我们深入了解一下Struts2中的注解。Struts2框架支持JSR-250和JSR-303等标准注解,同时也提供了一些自定义注解来增强功能。例如,`@Action`注解用于标记一个方法为Struts2的动作,这个方法将在用户请求时被...

    深入解析Spring Boot自动配置机制及其关键注解

    适合人群:具有一定Java编程经验和对Spring框架有一定了解的技术人员,尤其适用于想要深入了解Spring Boot工作机制的研发人员。 使用场景及目标:帮助开发者理解Spring Boot自动配置的具体实现,从而更好地利用...

    对Spring中注解怎么实现的一些基本原理

    本文将深入探讨Spring注解的基本原理,包括它们如何被解析、处理以及如何影响应用程序的生命周期。 首先,我们需要了解注解在Java语言中的本质。注解是一种元数据,允许程序员在源代码中嵌入信息,这些信息可以被...

    springMVC注解和非注解demo

    首先,让我们深入了解一下Spring MVC中的注解编程。Spring MVC注解使得开发变得更加简洁和直观,减少了XML配置文件的需求。以下是一些常见的注解: 1. `@Controller`:标记一个类作为Spring MVC的控制器,处理来自...

    运行时注解demo

    在本“运行时注解demo”中,我们将深入探讨如何使用和处理运行时注解。 首先,注解(Annotation)主要有三种类型:源码保留(Source retention)、编译器保留(Compile-time retention)和运行时保留(Runtime ...

    Struts2 注解 Demo

    在`Struts2Demo`项目中,你还可以学习到如何配置Struts2的`struts-plugin.xml`和`struts.xml`文件,以便启用注解支持,并了解如何在web.xml中配置过滤器,确保Struts2框架能正确拦截请求。 总结,Struts2注解是...

Global site tag (gtag.js) - Google Analytics