Java 注解

来源:互联网 发布:美国大律师 知乎 编辑:程序博客网 时间:2024/04/30 03:42

I. 简介

注解(Anotation) 在程序中有广泛的应用. 比如,在重写方法时,方法上的@Override便是注解.
而注解分为了两类,一为标准注解,一为元注解.

标准注解

Java JDK 中自带了三种标准注解.

@Override: 当前的方法将会覆盖超类方法.
@Deprecated: 如果程序员使用了该注解标注的元素,编译器会发出警告.
@SuppressWarnings: 关掉不当的编译器警示信息.

元注解

四种元注解则是用于新注解的创建.

@Target: 表明该注解可用的地方. 需要填入ElementType 的参数.
@Retention: 在什么级别保存注解信息. 需要填入RetentionPolicy 的参数.
@Documented: 将注解保存在Javadoc 中.
@Inherited: 允许子类继承父类.

首先,Java 允许对一个元素标记多个注解;其次,注解是不能被继承的.
注解和反射机制(Reflection) 一起使用对于开发非常有用.

II. 标准注解实例

@Override

@Override 应该是非常常见的注解.

class Person {    @Override    public String toString() {        return "Person";    }}

比如重写Object类的toString()上,编译器就会自动的插入@Override注解.

@Deprecated

public class Multiply {    public static double multiply(int x, int y) {        return ((double) x) * y;    }    public static void main(String [] args) {        System.out.println(multiply(5, 10));    }}

此时,该方法可以使用,并且编译器不会发出警告.
但当加上@Deprecated 注解后,调用方法处会被加上一道斜线,表明此方法已经被废弃.

III. 元注解实例

创建注解

在自己创建新的注解时,常常会使用元注解配合来规定该注解的一些特性.

@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)public @interface Finished {    String value();    int id() default -1;    String time() default "";}

在此处,一个Finished的注解被定义了,并使用了两个元注解进行标记.
在这里,@Target中的ElementType.Method表明这个注解只能被用于标记方法;而@RetentionRetentionPolicy.RUNTIME表明这个注解即使在程序运行时也会被保存,因此可以通过反射机制来获取使用该注解的方法的信息.
Finished中,两个变量分别代表了在使用此注解时需要输入的参数. id()default -1 表示在没有id() 参数的情况下,id()的值将会被设为-1. 而value()因为没有default 值,所以在使用该注解时一定要输入String 值.


注解中的可用元素包括:

基本类型;
Class;
String;
enum;
Annotation;
以上类型的数组.

因为Java 注解元素不允许有null 值,所以int、float 等值通常设为-1,String 通常设置为”” 已表示默认值.
另一个值得注意的是,Java 的注解中,如果除value()外每一个元素都有default 值,但value()没有,那么在使用注解时输入的参数就是直接对应value()的.

使用注解

public class Task {    public void wash() {        System.out.println("wash");    }    @Finished("not worked out")    public void run() {        throw new NotImplementedException();    }    @Finished(value = "I like it", id = 5, time =  "20160428")    public void sleep() {        System.out.println("sleep");    }}

Task这个类中,用刚才定义的Finished注解标记了两个方法.
在第一个被标记的方法(run())上,只输入了一个参数,默认为给注解的value()赋值. 而第二个方法(sleep())上,因为存在多个元素的赋值,所以需要指明key-value 的对应关系.


看到这里,相信很多人会问:注解到底有什么用?
接下来使用反射机制的注解处理器将会解答这个问题.

处理器

public class Processor {    public static void main(String [] args)             throws ClassNotFoundException {        if (args.length < 1) {            System.out.println("argument needed");            System.exit(0);        }        for (String className: args) {            System.out.println(className + ".class");            Class<?> cl = Class.forName(className);            for (Method method : cl.getDeclaredMethods()) {                Finished finished =                     method.getAnnotation(Finished.class);                if (finished != null) {                    System.out.println("method " + method.getName() +                            " has annotations:\n comment: " +                            finished.value() + "\n  id: " +                             finished.time());                    System.out.println("---------------------" +                     "-----------------");                } else {                    System.out.println("method " + method.getName() +                            " has no annotations");                    System.out.println();                }            }        }    }}output://Task.classmethod run has annotations: comment: not worked out  id: -1 finished time: --------------------------------------method sleep has annotations: comment: I like it  id: 5 finished time: 20160428--------------------------------------method wash has no annotations

这里,通过反射的使用,我们获得了Task 类中方法的注解信息.
配合反射和注解,我们可以完成很多任务:查看当前任务完成的进展、抽取类中的特定方法等等.
另外,因为run()方法只传递了一个参数,所以另外两个元素的值都为默认值.

0 0
原创粉丝点击