1. 注解简介
注解(Annotation)也称为元数据(MetaData)。可以用于修饰包、类、方法、属性、构造器、局部变量等数据元素。可以再原有逻辑不变的情况下,在源文件中嵌入一些补充信息。
注解可以在编译、类加载、运行时被读取。
2. 基本注解
2.1 @Override
被@Override修饰的方法必须要重写父类的方法。起到说明作用。
查看该注解的源码可知:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}
- 该注解只能用于修饰方法。
- 该注解只能保留在源代码中,编译器将会直接丢弃该注解。
通过一个案例来加加深理解:
public class MyOverride {
public static void main(String[] args) {
Dog dog = new Dog();
dog.calls();
}
}
class Animal{
public void calls(){
System.out.println("Animal发出了叫声");
}
}
class Dog extends Animal{
@Override // 使用Override注解说明该方法重写了父类的方法
public void calls(){
System.out.println("汪汪~");
}
}
运行程序,可以发现在子类Dog中是否添加@Override都可以正常运行,这说明是否添加@Override注解,子类都会重写父类的方法。那么添加@Override注解的作用是什么?再看如下案例:
class Animal{
public void calls(){
System.out.println("Animal发出了叫声");
}
}
class Dog extends Animal{
@Override // 使用@Override修饰了一个在父类中不存在的方法。
public void run(){
System.out.println("汪汪~");
}
}
运行程序,发现抛出异常。因此,通过以上案例,我们可以总结出@Overide的作用之一:在程序运行时,告诉编译器要检测该方法是否在父类中存在,起到语法校验的作用。防止在子类中想重写父类方法但却写错的这些低级错误。
📓 小结:
- 用于修饰方法
- 只能保留在源代码,无法通过反射获取该注解信息。
- 说明作用
- 语法校验作用
2.2 @Deprecated
被注解@Deprecated修饰的元素表示已经过时,在不久的将来会去掉。
public class MyDeprecated {
public static void main(String[] args) {
Cat.run();
}
}
@Deprecated // 使用@Deprecated注解修饰该类,表示该类及其子元素已经弃用
class Cat{
public static void run(){
System.out.println("run run run ~");
}
}
可以发现当在其他地方调用被@Deprecated注解修饰的类时,该类会被中划线划掉。即不推荐使用,但能够使用。 起到提示尽快更新过渡的作用。
查看该基本注解的源码可知:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})
public @interface Deprecated {
}
- 该注解可以用于修饰:构造器、成员变量、局部变量、方法、包、参数、类等所有元素。
- 该注解能够存在于字节码文件中,并且JVM可以获得注解信息,也可以通过反射获取注解信息。
📓小结:
- 可以用于修饰所有元素。
- 表示已经弃用,起到提示尽快更新过渡的作用。
- JVM可以获得注解信息,也可以通过反射获取注解信息。
2.3 @SuppressWarnings
被该注解修饰的元素及其子元素将会被取消显示指定的编译器警告。使用参数value来指定要被抑制的类型,常用的值如下:
| 关键字 | 用途 |
|---|---|
| all | 抑制所有警告 |
| boxing | 抑制装箱、拆箱操作时候的警告 |
| cast | 抑制映射相关的警告 |
| dep-ann | 抑制启用注释的警告 |
| deprecation | 抑制过期方法警告 |
| fallthrough | 抑制在 switch 中缺失 breaks 的警告 |
| finally | 抑制 finally 模块没有返回的警告 |
| hiding | 抑制相对于隐藏变量的局部变量的警告 |
| incomplete-switch | 忽略不完整的 switch 语句 |
| nls | 忽略非 nls 格式的字符 |
| null | 忽略对 null 的操作 |
| rawtypes | 使用 generics 时忽略没有指定相应的类型 |
| restriction | 抑制禁止使用劝阻或禁止引用的警告 |
| serial | 忽略在 serializable 类中没有声明 serialVersionUID 变量 |
| static-access | 抑制不正确的静态访问方式警告 |
| synthetic-access | 抑制子类没有按最优方法访问内部类的警告 |
| unchecked | 抑制没有进行类型检查操作的警告 |
| unqualified-field-access | 抑制没有权限访问的域的警告 |
| unused | 抑制没被使用过的代码的警告 |
@SuppressWarnings(value = "{all}") // 去掉该类中的所有警告
public class MySupperWarnings {
public static void main(String[] args) {
List<String> myList = new ArrayList();
}
}
分析源代码可知:
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {
String[] value();
}
- 该注解可以用于修饰除包、注解外的其他元素。
- 该注解只能保留在源代码中。
2.4 @FunctionalInterface
该注解用于指定某个接口必须时函数式接口,否则编译器则会抛出异常。
函数式接口:接口中只有一个抽象方法,但可以包含多个默认方法(default)和多个静态方法(static),这样的接口就是函数式接口。函数式接口是为了lambda表达式准备的。
@FunctionalInterface
interface ins{
default void bar1(){
System.out.println("这是第一个默认方法");
}
default void bar2(){
System.out.println("这是第一个默认方法");
}
static void bb(){
System.out.println("这是一个static方法");
}
// 只有一个抽象方法
void test();
// void test2();
}
当接口中含有多个抽象方法时:
Error:(14, 1) java: 意外的 @FunctionalInterface 注释
annotation.ins 不是函数接口
在 接口 annotation.ins 中找到多个非覆盖抽象方法
查看源码可知:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface FunctionalInterface {}
- 该注解信息可以通过反射获得。
- 该注解只能用于修饰接口。
3. 元注解
3.1 @Retention
@Retention 用于描述注解的生命周期,也就是该注解被保留的时间长短。通过value参数来设置生命周期:
| 序号 | value | 作用 |
|---|---|---|
| 1 | RetentionPolicy.SOURCE | 在源文件中有效(即源文件保留) |
| 2 | RetentionPolicy.SOURCE | 在 class 文件中有效(即 class 保留) |
| 3 | RetentionPolicy.RUNTIME | 在运行时有效(即运行时保留) |
生命周期大小排序为 SOURCE < CLASS < RUNTIME,前者能使用的地方后者一定也能使用。如果需要在运行时去动态获取注解信息,那只能用 RUNTIME 注解;如果要在编译时进行一些预处理操作,就用 CLASS注解;如果只是做一些检查性的操作,比如 @Override 和 @SuppressWarnings,则可选用 SOURCE 注解。
3.2 @Target
@Target 注解用来指定一个注解的使用范围,即被 @Target 修饰的注解可以用在什么地方。通过value参数来设置使用范围:
| 序号 | value | 作用 |
|---|---|---|
| 1 | ElementType.ANNOTATION_TYPE | 用于注解 |
| 2 | ElementType.CONSTRUCTOR | 用于构造方法 |
| 3 | ElementType.FIELD | 用于成员变量(包括枚举常量) |
| 4 | ElementType.LOCAL_VARIABLE | 用于局部变量 |
| 5 | ElementType.METHOD | 用于方法 |
| 6 | ElementType.PACKAGE | 用于包 |
| 7 | ElementType.PARAMETER | 用于类型参数(JDK 1.8新增) |
| 8 | ElementType.TYPE | 用于类、接口(包括注解类型)或 enum 声明 |
3.3 @Documented
用 @Documented 注解修饰的注解类会被 JavaDoc 工具提取成文档。默认情况下,JavaDoc 是不包括注解的。
3.4 Inherited
@Inherited 是一个标记注解,用来指定该注解可以被继承。使用 @Inherited 注解的 Class 类,表示这个注解会被子类自动继承。