Java学习之注解元数据

简介

注解也被称为元数据,它为我们在代码中添加信息提供了一种形式化的方法,使我们可以在稍后某个时刻非常方便地使用这些数据。

注解一定程度上是把元数据和源代码文件结合在一起,而不是保存在外部文档中这一大的趋势之下所催生的。

在Java中,有一些内置的注解,比如:

  • @Override:表示当前的方法顶柜将覆盖超类中的方法,如果拼写错误或者覆盖不符合标准,编译器就会发出错误提示。
  • @Deprecated:表示被修饰的元素已经被弃用,不建议程序员使用。
  • @SuppressWarnings:关闭不当的编译器警告信息
    除了这三个还有一些我们后面会提到


基本语法


注解定义

下面是一个注解的定义。可以看到,注解看起来很像接口的定义,事实上,与其他任何Java接口一样,注解也将会编译成class文件。

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

除了@符号以外,它很像一个空接口。

在定义注解时,会需要一些元注解,如@Target和@Retention。前者用来定义注解将应用于何处(类、方法还是域),后者定义该注解的可用级别(源代码,编译时,运行时)

在注解中,通常都会包含一些元素以表示某些之。当分析处理注解时,程序或工具可以利用这些值。注解中的元素看起来就像是接口的方法,唯一的区别就是我们可以指定其默认值。

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AnnotationDemo1 {
    public int id();
    public String description() default "no description";
}

注意,id和description类似方法定义。如果在使用该注解时没有给出description值,则该注解的处理器会使用此元素的默认值。

下面是此注解的使用示例

class demo{
    @AnnotationDemo1(id=1)
    public void f1(){
        
    }
    
    @AnnotationDemo1(id=2,description = "f2")
    public void f2(){}
}

元注解

Java目前只内置了三种标准注解(一开始提到的三个注解)以及四种元注解。元注解专职负责注解其他注解:

注解说明参数
@Target表示该注解可以用于什么地方CONSTRUCUOR:构造器
FIELD:域
LOCAL_VARIABLE:局部变量
METHOD:方法声明
PACKAGE:包声明
PARAMETER:参数说明
TYPE:类、接口(包括注解)或enum
@Rentention表示需要在什么级别保存该注解信息SOURCE:注解将被编译器丢弃
CLASS:注解在class文件中可用。会被jvm丢弃
RUNTIME:JVM在运行期间保留注解,因此可以通过反射机制读取注解信息
@Documented将此注解包含在javadoc中
@Inherited允许子类继承父类中的注解

大多数时候,我们需要定义自己的注解,并编写自己的处理器去处理他们



注解处理器

如果没有又来读取注解的工具,那注解也不会比注释更有用。使用注解的过程中,很重要的一个部分就是创建与使用注解处理器。JavaSE5拓展了反射机制的API,以帮助我们构造这类工具。

下面例子是一个简单的注解处理器,我们将用它来读取被自定义注解修饰的demo类,并使用反射查找@AnnotationDemo1标记

public class AnnotationDemo2 {
    public static void main(String[] args) {
        AnnotationDemo1Tracker.handleAnnotation(demo.class);
    }
}

class AnnotationDemo1Tracker{
    public static void handleAnnotation(Class<?> cl){
        for (Method method:cl.getDeclaredMethods()){
            AnnotationDemo1 annotationDemo1 = method.getAnnotation(AnnotationDemo1.class);
            if(annotationDemo1 != null){
                System.out.println(method.getName()+"---id:"+annotationDemo1.id()+"---description:"+annotationDemo1.description());
            }
        }
    }
}

上面例子中,注解处理器使用到了两个反射的方法:getDeclaredMethods()和getAnnotation(),它们都属于AnnotatedElement接口(Class、Method与Field等类都实现了该接口)。getAnnotation()方法返回指定类型的注解对象,如果目标方法上没有该类型的注解,则返回null。然后我们通过调用id()和description()方法从返回的注解中提取元素的值。


注解元素

注解中可用的元素类型如下所示:

  • 所有基本类型
  • String
  • Class
  • enum
  • Annotation
  • 以上类型的数组
    如果我们使用了其他类型,那编译器就会报错。注意包装类型也不被允许。注解也可以作为元素的类型,也就是说注解可以嵌套。这是一个非常有用的特性。

默认值限制

编译器对元素的默认值有非常严格的要求。首先,元素不能有不确定的值。也就是说,元素必须要么具有默认值,要么在使用注解时提供元素的值。
其次,对于非基本类型的元素,不论是默认值还是声明时的值,都不能为null。这个约束使得处理器很难表现一个元素的存在或者缺失状态,为了绕开这个约束,我们只能自己定义一些特殊的值,比如空字符串或者负数,用来标识一个元素不存在。


生成外部文件

我们在使用hibernate、struts2以及早期的Spring框架时会发现我们除了编写代码以外,还需要配置一些额外的配置文件。这就导致我们使用外部配置文件时,相当于拥有了同一个类的两个单独的信息源,这经常导致代码的同步问题。同时,它也要求开发者必须同时指导如何编写Java程序,以及如何描述文件。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

原来是肖某人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值