自定义注解使用场景
- 类属性自动赋值
- 验证对象属性完整性
- 代替配置文件功能(例如spring基于注解的配置)
- 可以生成文档(例如javadoc的@see@param)
自定义注解的实现
注解是插入到源码中使用其他工具可以对其进行处理的标签
下面是一个简单注解的实例
1
2
3
4public class MyClass{
...
pulbic void checkRandomInsertions()
}
在java中,注解是当作一个修饰符来使用的,它被置于注解项之前,中间没有分号;注解是代码的一部分
@Test 注解本身并不会做任何事情,它需要工具支持才会有用。例如,当测试一个类的时候,JUnit4 测试工具可能会调用所有标识为@Test 的方法。另一个工具可能会删除一个类文件的所有测试方法,以便在对这个类测试完毕后,不会将这些测试方法和程序装载在一起。
注解可以定义成包含元素的形式,例如:1
"10000") (timeout=
每个注解都必须通过一个注解接口进行定义。这些接口中的方法与注解中的元素相对应。例如,Junit 的注解Test可以用下面这个接口进行定义:1
2
3
4
5 (ElementType.METHOD)
(RetentionPolicy.RUNTIME)
public Test{
long timeout() default OL;
}
@interface声明创建了一个真正的java接口。处理注解的工具将接收那些实现了这个注解接口的对象。这类工具可以调用timeout方法来检索某个特定Test注解的timeout元素。
注解Target和Retention是元注解。他们注解了Test注解,即将Test注解标识成一个只能运用到方法上的注解,并且当类文件载入到虚拟机的时候,依然可以保留下来。
注解语法
注解接口
注解是由注解接口来定义的1
2
3
4modifiers AnnotationName{
elementDeclaration1;
elementDeclaration2;
}
每个元素声明都具有下面这种形式:1
type elementName();
或者1
type elementName() default value;
注解元素的类型为下列之一:
- 基本类型(int、short、long、byte、char、double、float或者boolean)
- String
- Class(具有一个可选的类型参数,例如Class<? extends MyClass>)
- enum类型
- 注解类型
- 由前面所述类型组成的数组(由数组组成的数组不是合法的元素类型)
下面是一个合法的元素声明的例子:1
2
3
4
5
6
7
8
9public BugReport{
enum Status { UNCONFIRMED, CONFIRMED, FIXED, NOTABUG};
boolean showStopper() default false;
String assignedTo() default "[none]";
Class<?> testCase() default Void.class;
Status status() default Status.UNCONFIRMED;
Reference ref() default @Reference;//an annotation type
String[] reprotedBy();
}
注解
每个注解都具有下面这种格式:1
(elementName1=value1, elementName2=value2, ...)
例如,1
"Harry", severity=10) (assignedTo=
元素的顺序无关紧要。下面这个注解和前面那个一样1
10, assignedTo="Harry") (severity=
如果某个元素的值并未指定,那么就使用声明的默认值。例如,考虑一下下面这个注解1
10) (severity=
元素assignedTo的值是字符串”[none]”
有两个特殊的快捷方式可以用来简化注解。
如果没有指定元素,要么是因为注解中没有任何元素,要么是因为所有的元素都使用默认值,那么你就不需要用圆括号了。例如,1
这样的注解也称为标记注解;
另一种快捷方式是单值注解。如果一个元素具有特殊的名字value,并且没有指定其他元素,那么你就可以忽略掉这个元素名以及等号。例如:1
2
3public ActionListenerFor{
String value();
}
可以将注解书写成如下格式:1
"yellow") (
而不是1
"yellow") (value=
注解各类声明
注解可以出现在许多地方,这些地方可以分为两类:声明和类型用法。声明注解可以出现在下列声明出:
- 包
- 类(包括enum)
- 接口(包括注解接口)
- 方法
- 构造器
- 实例域(包含enum常量)
- 局部变量
- 参数变量
- 类型参数
注解类型用法
声明注解提供了正在被声明的项的相关信息。例如,在下面的声明中1
public User getUser(@NonNull String userId)
就断言userId参数不为空
类型用法注解可以出现在下面的位置:
- 与泛化类型引元一起使用
- 数组中的任何位置
- 与超类和实现接口一起使用
与构造器调用一起使用:
1
new String(...)
与强制转型和instanceof检查一起使用
1
(if(text instanceof String) String)text,
与异常规约一起使用
- 与通配符和类型边界一起使用
- 与方法和构造器引用一起使用
注解this
了解一下1
2
3public class Point{
public boolean equals(@ReadOnly Point this, @ReadOnly Object other){...}
}
第一个参数被称为接收器参数,它必须被命名为this,而它的类型就是要构建的类。
标准注解
注解接口 | 应用场合 | 目的 |
---|---|---|
Deprecated | 全部 | 将项标记为过时 |
SuppressWarnings | 除了包和注解之外的所有情况 | 阻止某个给定类型的警告信息 |
SafeVarargs | 方法和构造器 | 断言varargs参数可安全使用 |
Override | 方法 | 检查该方法是否覆盖了某一个超类方法 |
FunctionalInterface | 接口 | 将接口标记为只有一个抽象方法的函数式接口 |
PostConstruct | 方法 | 被标记的方法应该在构造之后立即被调用 |
PreDestroy | 方法 | 被标记的方法应该在移除之前立即被调用 |
Resource | 类、接口、方法、域 | 在类或接口上:标记为在其他地方要用到的资源。在方法或域上:为“注入”而标记 |
Resources | 类、接口 | 一个资源组 |
Generated | 全部 | |
Target | 注解 | 指明可以应用这个注解的那些项 |
Retention | 注解 | 指明这个注解可以保留多久 |
Documented | 注解 | 指明这个注解应该包含在注解项的文档中 |
Inherited | 注解 | 指明当这个注解应用与一个类的时候,能够自动被它的子类继承 |
Repeatable | 注解 | 指明这个注解可以在同一个项上应用多次 |
用于编译的注解
用于管理资源的注解
元注解
源码级注解处理
注解处理
1 | javac -process ProcessorClassName1, ProcessorClassName2, ...sourceFiles |