22.0 第22章 注解 22.1 内置注解

第22章 注解

前一章我们探讨了反射,反射相关的类中都有方法获取注解信息,我们在前面章节中也多次提到过注解,注解到底是什么呢?在Java中,注解就是给程序添加一些信息,用字符@开头,这些信息用于修饰它后面紧挨着的其他代码元素,比如类、接口、字段、方法、方法中的参数、构造方法等。注解可以被编译器、程序运行时和其他工具使用,用于增强或修改程序行为等。

这么说比较抽象,下面我们会具体介绍。先介绍Java的一些内置注解,然后介绍一些框架和库的注解,了解了注解的使用之后,介绍怎么创建注解,如何利用反射查看注解信息,最后我们介绍注解的两个应用:定制序列化和依赖注入容器。

22.1 内置注解

Java内置了一些常用注解:@Override、@Deprecated、@SuppressWarnings,我们简要介绍。

1. @Override

@Override修饰一个方法,表示该方法不是当前类首先声明的,而是在某个父类或实现的接口中声明的,当前类“重写”了该方法,比如:

1
2
3
4
5
6
7
8
9
10
11
12
13
static class Base {
public void action() {};
}
static class Child extends Base {
@Override
public void action(){
System.out.println("child action");
}
@Override
public String toString() {
return "child";
}
}

Child的action方法重写了父类Base中的action方法,toString方法重写了Object类中的toString方法。这个注解不写也不会改变这些方法是“重写”的本质,那有什么用呢?它可以减少一些编程错误。如果方法有Override注解,但没有任何父类或实现的接口声明该方法,则编译器会报错,强制程序员修复该问题。比如,在上面的例子中,如果程序员修改了Base方法中的action方法定义,变为了:

1
2
3
static class Base {
public void doAction() {};
}

但是,程序员忘记了修改Child方法,如果没有Override注解,编译器不会报告任何错误,它会认为action方法是Child新加的方法,doAction会调用父类的方法,这与程序员的期望是不符的,而有了Override注解,编译器就会报告错误。所以,如果方法是在父类或接口中定义的,加上@Override吧,让编译器帮你减少错误。

2. @Deprecated

@Deprecated可以修饰的范围很广,包括类、方法、字段、参数等,它表示对应的代码已经过时了,程序员不应该使用它,不过,它是一种警告,而不是强制性的,在IDE如Eclipse中,会给Deprecated元素加一条删除线以示警告。比如,Date中很多方法就过时了:

1
2
3
4
@Deprecated
public Date(int year, int month, int date)
@Deprecated
public int getYear()

在声明元素为@Deprecated时,应该用Java文档注释的方式同时说明替代方案,就像Date中的API文档那样,在调用@Deprecated方法时,应该先考虑其建议的替代方案。

从Java 9开始,@Deprecated多了两个属性:since和forRemoval。since是一个字符串,表示是从哪个版本开始过时的;forRemoval是一个boolean值,表示将来是否会删除。比如,Java 9中Integer的一个构造方法就从版本9开始过时了,其代码为:

1
2
3
4
@Deprecated(since="9")
public Integer(int value) {
this.value = value;
}

3. @SuppressWarnings

@SuppressWarnings表示压制Java的编译警告,它有一个必填参数,表示压制哪种类型的警告,它也可以修饰大部分代码元素,在更大范围的修饰也会对内部元素起效,比如,在类上的注解会影响到方法,在方法上的注解会影响到代码行。对于Date方法的调用,可以这样压制警告:

1
2
3
4
5
@SuppressWarnings({"deprecation", "unused"})
public static void main(String[] args) {
Date date = new Date(2017, 4, 12);
int year = date.getYear();
}

Java提供的内置注解比较少,我们日常开发中使用的注解基本都是自定义的。不过,一般也不是我们定义的,而是由各种框架和库定义的,我们主要还是根据它们的文档直接使用。