注释,J2SE 5.0 (Tiger) 中的新功能,将非常需要的元数据工具引入核心 Java 语言。该系列文章分为两部分,在这第 1 部分中,作者 Brett McLaughlin 解释了元数据如此有用的原因,向您介绍了 Java 语言中的注释,并研究了 Tiger 的内置注释。
<!--START RESERVED FOR FUTURE USE INCLUDE FILES--><!-- include java script once we verify teams wants to use this and it will work on dbcs and cyrillic characters --> <!--END RESERVED FOR FUTURE USE INCLUDE FILES-->
编程的一个最新的趋势,尤其是在 Java 编程方面,是使用 元数据。简单地说,元数据就是 关于数据的数据。元数据可以用于创建文档,跟踪代码中的依赖性,甚至执行基本编译时检查。许多元数据工具,如 XDoclet(请参阅 参考资料),将这些功能添加到核心 Java 语言中,暂时成为 Java 编程功能的一部分。
直到可以使用 J2SE 5.0(也叫做 Tiger,现在是第二个 beta 版本),核心 Java 语言才最接近具有 Javadoc 方法的元数据工具。您使用特殊的标签集合来标记代码,并执行 javadoc
命令来将这些标签转化成格式化的 HTML 页面,该页面说明标签所附加到的类。然而,Javadoc 是有缺陷的元数据工具,因为除了生成文档之外,您没有固定、实用、标准化的方式来将数据用于其他用途。HTML 代码经常混入到 Javadoc 输出中这一事实甚至更进一步降低了其用于任何其他目的的价值。
Tiger 通过名为 注释的新功能将一个更通用的元数据工 具合并到核心 Java 语言中。注释是可以添加到代码中的修饰符,可以用于包声明、类型声明、构造函数、方法、字段、参数和变量。Tiger 包含内置注释,还支持您自己编写的定制注释。本文将概述元数据的优点并向您介绍 Tiger 的内置注释。本系列文章的 第 2 部分将研究定制注释。我要感谢 O'Reilly Media, Inc.,他们非常慷慨地 允许我在本文中使用我关于 Tiger 的书籍的“注释”一章中的代码示例(请参阅 参考资料)。
元数据的价值
一 般来说,元数据的好处分为三类:文档编制、编译器检查和代码分析。代码级文档最常被引用。元数据提供了一种有用的方法来指明方法是否取决于其他方法,它们 是否完整,特定类是否必须引用其他类,等等。这确实非常有用,但对于将元数据添加到 Java 语言中来说,文档编制可能是
最不相关的理由。Javadoc 已经提供了非常容易理解和健壮的方法来文档化代码。另外,当已经存在文档编制工具,并且在大多数时候都工作得很好时,谁还要编写文档编制工具?
编译器检查
元数据更重要的优点是编译器可以使用它来执行基本的编译时检查。例如,您将在本文后面的
Override 注释中 看到 Tiger 引入了一个这样的注释,用于允许您指定一种方法覆盖超类中的另一种方法。Java 编译器可以确保在元数据中指明的行为实际发生在代码级别。如果从来没有找出过这种类型的 bug,这样做似乎有点傻,但是大多数年龄很大的 Java 编程老手都曾经花费至少多个晚上来查明他们的代码为什么不能用。当最后认识到方法的参数有错,且该方法实际上
没有 覆盖超类中的方法时,您可能更感到难受。使用元数据的工具有助于轻松地查明这种类型的错误,从而可以节省那些晚上来看长期进行的 Halo 联赛。
|
JSR 175
JSR 175, Java 编程语言的元数据工具,为将元数据合并到核心 Java 语言中提供了正式理由和说明(请参阅 参考资料)。根据 JSR,注释“不直接影响程序的语义。然而,开发和部署工具可以读取这些注释,并以某种形式处理这些注释,可能生成其他 Java 编程语言源文件、XML 文档或要与包含注释的程序一起使用的其他构件。”
|
|
代码分析
可 以证明,任何好的注释或元数据工具的最好功能就是可以使用额外数据来分析代码。在一个简单的案例中,您可能构建代码目录,提供必需的输入类型并指明返回类 型。但是,您可能想,Java 反射具有相同的优点;毕竟,可以为所有这些信息内省代码。这从表面上看似乎是正确的,但是在实际中通常不使用。许多时候,方法作为输入接受的或者作为输出 返回的类型实际上不是该方法想要的类型。例如,参数类型可能是
Object
,但方法可能仅使用
Integer
。这在好些情况下很容易发生,比如在方法被覆盖而超类使用常规参数声明方法时,还有正在进行许多序列化的系统中也容易发生。在这两种情况中,元数据可以指示代码分析工具,虽然参数类型是
Object
,但
Integer
才是真正需要的。这类分析非常有用,但也不能夸大它的价值。
在 更复杂的情况下,代码分析工具可以执行所有种类的额外任务。示例 du jour 是 Enterprise JavaBean (EJB) 组件。甚至简单 EJB 系统中的依赖性和复杂性都非常令人吃惊。您具有了 home 接口和远程接口,以及本地接口和本地 home 接口,还有一个实现类。保持所有这些类同步非常困难。但是,元数据可以提供这个问题的解决放案。好的工具(还是要提一下 XDoclet)可以管理所有这些依赖性,并确保无“代码级”连接、但有“逻辑级”捆绑的类保持同步。元数据在这里确实可以发挥它的作用。
注释的基本知识
现在已经了解了元数据的好处,我将介绍 Tiger 中的注释。注释采用“at”标记形式 (
@
),后面是注释名称。然后在需要数据时,通过
name=value
对向注释提供数据。每次使用这类表示法时,就是在生成注释。一段代码可能会有 10 个、50 个或更多的注释。不过,您将发现多个注释都可能使用相同的
注释类型。类型是实际使用的结构,在特定上下文中,注释本身是该类型的具体使用(请参阅侧栏
注释或注释类型?)。
|
注释或注释类型?
是否对什么是注释与什么是注释类型感到迷惑?了解这个的最简单方法就是对比所熟悉的 Java 语言概念来想。可以定义一个类(例如 Person ),则在 JVM 中将总是仅有该类的一个版本(假设没有进行麻烦的类路径设置)。然而,在任何给定时间,可能会使用该类的 10 个或 20 个 实例。仍然是只有一个 Person 类,但是它以不同的方式使用多次。注释类型和注释也是这样。注释类型类似于类,注释类似于该类的实例。
|
|
注释分为三个基本种类:
- 标记注释没有变量。注释显示简单,由名称标识,没有提供其他数据。例如,
@MarkerAnnotation
是标记注释。它不包含数据,仅有注释名称。
- 单一值注释与标记注释类似,但提供一段数据。因为仅提供很少的一点数据,所以可以使用快捷语法(假设注释类型接受此语法):
@SingleValueAnnotation("my data")
。除了 @
标记外,这应该与普通的 Java 方法调用很像。
- 完整注释有多个数据成员。因此,必须使用更完整的语法(注释不再像普通的 Java 方法):
@FullAnnotation(var1="data value 1", var2="data value 2", var3="data value 3")
。
除了通过默认语法向注释提供值外,还可以在需要传送多个值时使用名称-值对。还可以通过花括号为注释变量提供值数组。清单 1 显示了注释中的值数组的示例。
清单 1. 在注释中使用按数组排列的值
@TODOItems({ // Curly braces indicate an array of values is being supplied @TODO( severity=TODO.CRITICAL, item="Add functionality to calculate the mean of the student's grades", assignedTo="Brett McLaughlin" ), @TODO( severity=TODO.IMPOTANT, item="Print usage message to screen if no command-line flags specified", assignedTo="Brett McLaughlin" ), @TODO( severity=TODO.LOW, item="Roll a new website page with this class's new features", assignedTo="Jason Hunter" ) })
|
清单 1 中的示例并没有乍一看那样复杂。 TODOItems
注释类型有一个具有值的变量。这里提供的值比较复杂,但 TODOItems
的使用实际与单一值注释类型相符,只是这里的单一值是数组而已。该数组包含三个 TODO
注释,其中每个注释都是多值的。逗号分隔每个注释内的值,以及单个数组内的值。非常容易,是吧?
但是我讲的可能超前了些。 TODOItems
和 TODO
是 定制注释, 是本系列文章第 2 部分中的主题。但是我想让您看到,即使复杂注释(清单 1 几乎是最复杂的注释)也不是非常令人害怕的。当提到 Java 语言的标准注释类型时,将很少看到如此复杂的情况。正如将在下面三个部分了解到的,Tiger 的基本注释类型的使用都极其简单。
Override 注释
Tiger 的第一个内置注释类型是
Override
。
Override
应该仅用于方法(不用于类、包声明或其他构造)。它指明注释的方法将覆盖超类中的方法。清单 2 显示了简单的示例。
清单 2. 操作中的 Override 注释
package com.oreilly.tiger.ch06; public class OverrideTester { public OverrideTester() { } @Override public String toString() { return super.toString() + " [Override Tester Implementation]"; } @Override public int hashCode() { return toString().hashCode(); } }
|
清单 2 应该很容易理解。 @Override
注释对两个方法进行了注释 — toString()
和 hashCode()
,来指明它们覆盖 OverrideTester
类的超类 ( java.lang.Object
) 中的方法的版本。开始这可能看起来没什么作用,但它实际上是非常好的功能。如果不覆盖这些方法,根本 无法 编译此类。该注释还确保当您将 toString()
弄乱时,至少还有某种指示,即应该确保 hashCode()
仍旧匹配。
当编码到很晚且输错了某些东西时,此注释类型真的可以发挥很大的作用,如清单 3 中所示。
清单 3. 使 Override 注释捕获打字稿
package com.oreilly.tiger.ch06; public class OverrideTester { public OverrideTester() { } @Override public String toString() { return super.toString() + " [Override Tester Implementation]"; } @Override public int hasCode() { return toString().hashCode(); } }
|
在清单 3 中, hashCode()
错误地输入为 hasCode()
。注释指明 hasCode()
应该覆盖方法。但是在编译中, javac
将发现超类 ( java.lang.Object
) 没有名为 hasCode()
的方法可以覆盖。因此,编译器将报错,如图 1 中所示。
图 1. 来自 Override 注释的编译器警告
|
缺少的功能
在单一值注释类型中,如果 Deprecated 允许包含错误类型消息将更好。然后,当用户使用声明为过时的方法时,编译器可以打印消息。该消息可以指明使用方法的结果如何重要,说明何时将停止方法,甚至建议备用方法。可能 J2SE 的下一版本(“Mustang”,他们这样命名)将提供这种功能。
|
|
这个便捷的小功能将帮助快速捕获打字稿。
Deprecated 注释
下一个标准注释类型是
Deprecated
。与
Override
一样,
Deprecated
是标记注释。正如您可能期望的,可以使用
Deprecated
来对不应再使用的方法进行注释。与
Override
不一样的是,
Deprecated
应该与正在声明为过时的方法放在同一行中(为什么这样?说实话我也不知道),如清单 4 中所示。
清单 4. 使用 Deprecated 注释
package com.oreilly.tiger.ch06; public class DeprecatedClass { @Deprecated public void doSomething() { // some code } public void doSomethingElse() { // This method presumably does what doSomething() does, but better } }
|
单独编译此类时,不会发生任何不同。但是如果通过覆盖或调用来使用声明为过时的方法,编译器将处理注释,发现不应该使用该方法,并发出错误消息,如图 2 中所示。
图 2. 来自 Deprecated 注释的编译器警告
注意需要开启编译器警告,就像是必须向 Java 编译器指明想要普通的声明为过时警告。可以使用下列两个标记之一和 javac
命令: -deprecated
或新的 -Xlint:deprecated
标记。
SuppressWarnings 注释
从 Tiger “免费”获得的最后一个注释类型是
SuppressWarnings
。发现该类型的作用应该不难,但是
为什么该注释类型如此重要通常不是很明显。它实际上是 Tiger 的所有新功能的副功能。例如,以泛型为例;泛型使所有种类的新类型安全操作成为可能,特别是当涉及 Java 集合时。然而,因为泛型,当使用集合而
没有 类型安全时,编译器将抛出警告。这对于针对 Tiger 的代码有帮助,但它使得为 Java 1.4.x 或更早版本编写代码非常麻烦。将不断地收到关于根本无关的事情的警告。如何才能使编译器不给您增添麻烦?
SupressWarnings
可以解决这个问题。 SupressWarnings
与 Override
和 Deprecated
不同, 是具有变量的 — 所以您将单一注释类型与该变量一起使用。可以以值数组来提供变量,其中每个值指明要阻止的一种特定警告类型。请看清单 5 中的示例,这是 Tiger 中通常会产生错误的一些代码。
清单 5. 不是类型安全的 Tiger 代码
public void nonGenericsMethod() { List wordList = new ArrayList(); // no typing information on the List wordList.add("foo"); // causes error on list addition }
|
图 3 显示了清单 5 中代码的编译结果。
图 3. 来自非标准代码的编译器警告
清单 6 通过使用 SuppressWarnings
注释消除了这种问题。
清单 6. 阻止警告
@SuppressWarings(value={"unchecked"}) public void nonGenericsMethod() { List wordList = new ArrayList(); // no typing information on the List wordList.add("foo"); // causes error on list addition }
|
非常简单,是吧?仅需要找到警告类型(图 3 中显示为“unchecked”),并将其传送到 SuppressWarnings
中。
SuppressWarnings
中变量的值采用数组,使您可以在同一注释中阻止多个警告。例如, @SuppressWarnings(value={"unchecked", "fallthrough"})
使用两个值的数组。此功能为处理错误提供了非常灵活的方法,无需进行大量的工作。
分享到:
相关推荐
2. **元数据驱动**:可能依赖于数据库元数据或其他数据源来生成与数据模型相关的代码。 3. **代码质量**:生成的代码应遵循良好的编程规范,例如驼峰命名法、注释规范等。 4. **可扩展性**:允许添加新的生成规则...
注解是一种在代码中添加元数据的方式,它允许程序员在源代码上添加一些信息,这些信息可以被编译器或运行时环境用来执行特定的任务。例如,验证输入、生成文档、实现依赖注入等。本文将深入探讨Java 1.5中的注解以及...
16. **注解(Annotation)**:注解为代码添加元数据,有助于编译器、构建工具或运行时环境进行处理。学习自定义注解和预定义注解的应用,可以提升代码的维护性和扩展性。 17. **IO与NIO**:了解Java的旧版IO流和非...
在每个Java源文件的开头,应包含一个C语言风格的注释,用于记录版本信息、作者及日期等元数据。示例: ```java /* * ClassName * * Version information * * Date * * Copyright notice */ ``` #### 六、...
2. **元数据解析**:通常,代码生成器需要从数据库或其他数据源获取元数据,例如表结构、字段类型等,这可能涉及到JDBC或ORM框架如Hibernate、MyBatis的使用。 3. **代码模板设计**:开发者需要设计符合项目规范的...
MBG支持从数据库元数据自动创建Java类和XML映射文件,从而避免手动编写这些重复性的代码。 在"mybatis生成代码工具(带注释)"中,重点是MBG的注释功能。注释在编程中起着至关重要的作用,它们提供了代码的解释和...
通过注释,我们可以向代码添加更多的元数据,使得在运行时或编译时可以基于这些信息做出决策。 Java提供了几种内置的注释,这些注释可以直接应用到代码的不同部分,例如: 1. `@Override`:确保方法重写父类的方法...
2. 插件配置文件:描述插件的元数据,如版本、作者、依赖等。 3. 构建脚本:可能包含Gradle或Maven等构建工具的配置,用于编译和打包插件。 4. 测试用例:验证插件功能的测试代码,确保插件在不同场景下的正确性。 5...
在这个项目中,我使用注释和Java代码配置创建了Spring项目。 运行应用程序 步骤1.安装Tomcat服务器并将其与IDE连接 第2步。添加lib文件夹中的Jar文件- Right click on Main project -> Properties-> Java Build Path...
标题中的“idea代码注释生成”指的是在IntelliJ IDEA这款强大的Java开发环境中,如何自动生成或美化代码注释的功能。IntelliJ IDEA是JetBrains公司出品的一款集成开发环境(IDE),深受Java开发者喜爱,其提供了丰富...
代码范例列表 第1章 示例描述:本章演示如何开始使用JDK进行程序的开发。 HelloWorldApp.java 第一个用Java开发的应用程序。 firstApplet.java 第一个用Java开发的Applet小程序。 firstApplet.htm 用来装载...
这种机制借鉴了类似Java的Lombok库,使得开发者可以在注释中添加元数据,指示代码生成器应该如何操作。通过这种方式,开发者可以定制化地创建模型类、getter/setter方法、构造函数以及其他重复性代码。 例如,如果...
Java 中的注解(Annotation)是一种元数据,提供了一种灵活的方式来处理代码中的元数据。注解可以用来生成文档、跟踪代码依赖性、执行编译时格式检查、代替已有的配置文件等。 什么是元数据 元数据是关于数据的...
而Java注解是一种元数据,可以被编译器或者JVM在编译时或运行时读取,用于执行特定的任务,如代码生成、验证等。 生成接口文档的传统方式是手动编写,这既耗时又容易出错。本框架或工具的目标就是自动化这个过程,...
javax.imageio.metadata 用于处理读写元数据的 Java Image I/O API 的包。 javax.imageio.plugins.bmp 包含供内置 BMP 插件使用的公共类的包。 javax.imageio.plugins.jpeg 支持内置 JPEG 插件的类。 javax....
Java注释是一种元数据,允许程序员向源代码中添加非执行信息,这些信息可以被编译器、IDE或其他工具读取并用于各种目的。在Java中,有三种类型的注释:单行注释、多行注释和文档注释。 标题"java-annotations"直接...
Java代码注释是编程实践中不可或缺的一部分,它有助于提高代码的可读性和维护性。下面将详细阐述Java代码注释的一些规范和最佳实践。 1. **注释形式统一**: - 保持一致性是关键。在同一个项目中,注释应该采用...
2. **数据库反向工程**:许多代码生成工具支持从数据库元数据生成实体类、DAO接口及其实现、Mapper XML文件等。例如,MyBatis的MyBatis Generator就是这类工具,它可以解析数据库表结构,自动生成与之对应的Java代码...
你需要添加代码,从数据库元数据中获取字段的注释,并将其插入到Java字段的Javadoc注释中。 4. **扩展API**:为了不破坏原有功能,你可能需要创建一个新的生成器类,继承自`JavaModelGenerator`,并重写上述方法。...