java annotation详解_Java 注解详解

本文部分摘自 On Java 8

基本语法

注解是 Java 5 所引入的众多语言变化之一,是附加在代码中的一些元信息,用于一些工具在编译、运行时进行解析和使用,起到说明、配置的功能。注解不会也不能影响代码的实际逻辑,仅仅起到辅助性的作用,包含在 java.lang.annotation 包中

注解的语法十分简单,只要在现有语法中添加 @ 符号即可,java.lang 包提供了如下五种注解:

@Override

表示当前的方法定义将覆盖基类的方法,如果你不小心把方法签名拼错了,编译器就会发出错误提示

@Deprecated

如果使用该注解的元素被调用,编译器就会发出警告信息,表示不鼓励程序员使用

@SuppressWarnings

关闭不当的编译器警告信息

@SafeVarargs

禁止对具有泛型可变参数的方法或构造函数的调用方发出警告

@FunctionalInterface

声明接口类型为函数式接口

定义注解

注解的定义看起来和接口的定义很像,事实上它们和其他 Java 接口一样,也会被编译成 class 文件

@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)public @interface TestAnnotation {}

除开 @ 符号, @Test 的定义看起来更像一个空接口。注解的定义也需要一些元注解,元注解用于注解其他的注解

注解

解释

@Target

表示注解可以用于哪些地方。可能的 ElementType 参数包括:

CONSTRUCTOR:构造器的声明

FIELD:字段声明(包括 enum 实例)

LOCAL_VARIABLE:局部变量声明

METHOD:方法声明

PACKAGE:包声明

PARAMETER:参数声明

TYPE:类、接口(包括注解类型)或者 enum 声明

@Retention

表示注解信息保存的时长。可选的 RetentionPolicy 参数包括:

SOURCE:注解将被编译器丢弃

CLASS:注解在 class 文件中可用,但是会被 VM 丢弃

RUNTIME:VM 将在运行期也保留注解,因此可以通过反射机制读取注解的信息

@Documented

将此注解保存在 Javadoc 中

@Inherited

允许子类继承父类的注解

@Repeatable

允许一个注解可以被使用一次或者多次(Java8)

不包含任何元素的注解称为标记注解,上例中的 @Test 就是标记注解。注解通常也会包含一些表示特定值的元素,当分析处理注解的时候,程序可以利用这些值。注解的元素看起来就像接口的方法,但可以为其指定默认值

@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)public @interface TestAnnotation { int id(); String description() default "no description";}....public class TestUtils { // 在方法上使用注解 @TestAnnotation @UseCase(id = 47, description = "description") public void test() { ... }}

注解元素可用的类型如下所示,如果使用了其他类型,编译器就会报错:

所有基本类型(int、float、boolean 等)

String

Class

enum

Annotation

以上类型的数组

如果没有给出 description 的值,在分析处理这个类的时候会使用该元素的默认值。元素的默认值不能有不确定的值,也就是说,元素要么有默认值,要么就在使用注解时提供元素的值

这里还有另外一个限制:任何非基本类型的元素,无论是在源代码声明时还是在注解接口中定义默认值时,都不能使用 null 作为值。如果我们希望表现一个元素的存在或者缺失的状态,可以自定义一些特殊的值,比如空字符串或者负数用于表达某个元素不存在

注解不支持继承,你不能使用 extends 关键字来继承 @interface

注解处理器

如果没有用于读取注解的工具,那么注解不会比注释更有用。使用注解中一个很重要的作用就是创建与使用注解处理器。Java 拓展了反射机制的 API 用于帮助你创造这类工具。同时他还提供了 javac 编译器钩子在编译时使用注解

下面是一个非常简单的注解处理器,我们用它来读取被注解的 TestUtils 类,并且使用反射机制来寻找 @TestAnnotation 标记

public class TestAnnotationTracker { public static void trackTestAnnotation(Class> cl) { for(Method m : cl.getDeclaredMethods()) { TestAnnotation ta = m.getAnnotation(TestAnnotation.class); if(ta != null) { System.out.println(ta.id() + "\n " + ta.description()); } } } public static void main(String[] args) { trackTestAnnotation(TestUtils.class); }}

这里用到了两个反射的方法:getDeclaredMethods() 和 getAnnotation(),getAnnotation() 方法返回指定类型的注解对象,在本例中就是 TestAnnotation,如果被注解的方法上没有该类型的注解,返回值就为 null。通过调用 id() 和 description() 方法来提取元素值

使用注解实现对象 - 数据库映射

当有些框架需要一些额外的信息才能与你的源代码协同工作,这种情况下注解就会变得十分有用。自定义例如对象/关系映射工具(Hibernate 和 MyBatis)通常都需要

假设你现在想提供一些基本的对象/关系映射功能,能够自动生成数据库表。你可以使用

首先创建一个用来映射数据库表的注解,用来修饰类、接口(包括注解类型)或者 enum 声明

@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)public @interface DBTable { String name() default "";}

如下是修饰字段的注解

@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)public @interface Constraints { boolean primaryKey() default false; boolean allowNull() default true; boolean unique() default false;}

public @interface SQLString { int value() default 0; String name() default ""; Constraints constraints() default @Constraints;}

@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)public @interface SQLInteger { String name() default ""; Constraints constraints() default @Constraints;}

@Constraints 代表了数据库通常提供的约束的一小部分,primaryKey(),allowNull() 和 unique() 元素都提供了默认值,大多数情况下,注解的使用者都不需要输入太多东西

另外两个 @interface 定义的是 SQL 类型。如果希望这个框架更有价值的话,我们应该为每个 SQL 类型都定义相应的注解。不过作为示例,两个元素足够了。这些 SQL 类型具有 name() 元素和 constraints() 元素。后者利用了嵌套注解的功能,将数据库列的类型约束信息嵌入其中。注意 constraints() 元素的默认值是 @Constraints,没有在括号中指明 @Constraints 元素的值,因此,constraints() 的默认值为所有元素都为默认值。如果要使得嵌入的 @Constraints 注解中的 unique() 元素为 true,并作为 constraints() 元素的默认值,你可以像如下定义:

public @interface Uniqueness { Constraints constraints() default @Constraints(unique = true);}

下面是一个简单的,使用了如上注解的类

@DBTable(name = "MEMBER")public class Member { @SQLString(30) String firstName; @SQLString(50) String lastName; @SQLInteger Integer age; @SQLString(value = 30, constraints = @Constraints(primaryKey = true)) String reference; static int memberCount; public String getReference() { return reference; } public String getFirstName() { return firstName; } public String getLastName() { return lastName; } @Override public String toString() { return reference; } public Integer getAge() { return age; }}

类注解 @DBTable 注解给定了元素值 ME.........

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值