java注解
注解是什么?
注解是元数据的一种形式,,为程序提供了一些数据,但是并不是程序的一部分。注解对代码并不直接地提供操作。
作用:
- 告知编译器一些信息,例如检查重写(@Override)、抑制警告(@SuppressWarnings)
- 编译器以及部署期 的处理: 软件工具可以处理注解去生成代码,xml文件
- 运行时处理:一些注解可以在运行时被检查到
基础
注解的格式
@Entity
@Author( name = "Benjamin Franklin", date = "3/27/2003" )
哪里可以被使用:
可以被用在 类、方法、字段、或者参数
public enum ElementType {
/* Class, interface (including annotation type), or enum declaration /
TYPE,
/* Field declaration (includes enum constants) /
FIELD,
/* Method declaration /
METHOD,
/* Formal parameter declaration /
PARAMETER,
/* Constructor declaration /
CONSTRUCTOR,
/* Local variable declaration /
LOCAL_VARIABLE,
/* Annotation type declaration /
ANNOTATION_TYPE,
/* Package declaration /
PACKAGE,
/*Type parameter declaration/
TYPE_PARAMETER,
/* Use of a type/
TYPE_USE
}
在java8 中,注解也可以用到type上
Class instance creation expression:
new @Interned MyObject();
Type cast:
myString = (@NonNull String) str;
implements clause:
class UnmodifiableList
@Readonly List<@Readonly T> { ... }
Thrown exception declaration:
void monitorTemperature() throws
@Critical TemperatureException { ... }
声明一个注解类型
用于代替注释
public class Generation3List extends Generation2List {
// Author: John Doe
// Date: 3/17/2002
// Current revision: 6
// Last modified: 4/12/2004
// By: Jane Doe
// Reviewers: Alice, Bill, Cindy
// class code goes here
}
要添加此相同的元数据与注释,首先需要去定义一个注解类型。语法如下:
注:注解里只允许基本类型,加上枚举,注解,String。
public @interface ClassPreamble {
String author();
String date();
int currentRevision() default 1;
String lastModified() default "N/A";
String lastModifiedBy() default "N/A";
// 使用数组
String[] reviewers();
}
注解的定义有点像interface,其实注解也是interface的一种形式。
注解的元素声明有点像接口的方法,注解的元素可以设置默认值。如果要使其出现在javadoc 中,需要加上@Document 注解
预定义注解类型
有些注解在java se api 中已经被定义好了。一些注解类型是被java 编译器所使用,有一些注解被用于其他注解上。
java语言中被使用
@Deprecated
@Override
@SuppressWarnings
@SafeVarargs
@FunctionalInterface
应用于其他注解
运用于其他注解的注解叫元注解
。在.java.lang.annotation
中被定义了一些元注解。
@Retention 注解用于指定注解被存储的时期
RetentionPolicy.SOURCE
这个意味着注解仅仅在源码中被保留,将会被编译器所忽略
RetentionPolicy.CLASS
这个意味着注解会被保留到编译期,但是会被jvm所忽略
RetentionPolicy.RUNTIME
这个意味着注解将会被保留到jvm中,也就是说可以在运行时中使用。
@Documented 在生成javadoc文档的时候,会显示这个注解的内容
@Target 表示这个注解作用的地方
ElementType.ANNOTATION_TYPE
可以被运用到注解类型ElementType.CONSTRUCTOR
可以运用到构造方法上.ElementType.FIELD
可以运用到字段或属性上ElementType.LOCAL_VARIABLE
可以被用到局部变量上.ElementType.METHOD
可以运用到方法上.ElementType.PACKAGE
可以在包路径上 .ElementType.PARAMETER
可以运用到方法参数上.ElementType.TYPE
可以被用到类 .
@Inherited 表示这个注解类可以从他的父类被继承,仅仅可以被用于类的声明。
@Repeatable 在java8 中被引入,这个标记的注解可以被多次声明
Type Annotation and pluggable type system
类型注解(type annotation) 被创建出来是为了支持改进对java程序的分析,是一种保证强类型检查的方式。在java8 版本中没有提供一种检查的框架,但是java 8 允许我们去写一个类型检查的框架,这个框架实现一个或多个模块,这些模块作为java编译器的插件。
例如: 你想要去保证程序中特定的参数永远不为null,你想要去避免出发空指针异常,可以去自定义一个插件去检查。你只需要去修改你的代码,把特定的变量加上标志能用null赋值的注解。就像这样
@Notnull String str;
当你去编译这个代码的时候,当这个编译器探测到一些潜在的问题的时候,会打印出警告。允许你去修改代码避免出现错误。当代码修正后,这个错误将不会出现在这个程序中。
重复注解 (repeating annotation)
很多时候,我们想在一个声明或类型上多次使用一个注解。在java8 中,重复注解提供了我们需要的这种功能。
为了兼容,重复注解是存储在注解容器(container annotation)中的,这个容器是由编译器自动生成的。为了编译器去完成这个,在代码中需要去实现两步声明。
第一步: 定义一个重复注解类
这个重复注解类一定要备Repeatable
元注解去标记。下面是定义一个@Schedule
重复注解:
@Repeatable(Schedules.class) // 容器类型
public @interface Schedule {
String dayOfMonth() default "first";
String dayOfWeek() default "Mon";
int hour() default 12;
}
这个元注解的值(圆括号中的值) ,就是java编译器生成的注解容器(container annotation存储注解 的类。(就是说,这个值,就是容器的类型,这个容器是用来存放的是注解)。在这个例子中,这个注解容器(container annotation) 的类型就是Schedules,因此,重复注解@Schedule
被存储在@Schedules
注解中。
第二步:声明一个容器注解类型
这个容器注解类型一定要包含一个value元素,他的类型是数组类型的。这个组件类型一定是重复注解的类型,声明Schedules
这个容器注解类型如下:
public @interface Schedules {
Schedule[] value(); // 一个Schedule 的数组
}
获取注解(Retrieving Annotation)
在反射api中有好几种获取注解的方法。有些方法可以获取一个注解。例如
[AnnotatedElement.getAnnotation(Class)]
如果圆括号中仅仅有一个注解(值),那就原封不动地返回一个注解(值),如果圆括号中有多个注解,也可以通过去获取注解容器去获取。以这种方式,代码可以继续运行。另一个就是,java 8 中新添的,可以一次性返回多个注解,例如AnnotatedElement.getAnnotations(Class
参考资料:java lesson
What is wrong with the following interface?
public interface House { @Deprecated void open(); void openFrontDoor(); void openBackDoor(); }
Consider this implementation of the
House
interface, shown in Question 1.public class MyHouse implements House { public void open() {} public void openFrontDoor() {} public void openBackDoor() {} }