- 注解(也被称为元数据)为在代码中添加信息提供了一种形式化的方法,使可以在稍后某个时刻非常方便地使用这些数据
Java标准注解
标准注解 | 注解作用 | 注解目标 |
---|
@Override | 表示当前的方法定义将覆盖超类中的方法,方法名对不上被覆盖的方法,编译器就会发出错误提示 | @Target(value=METHOD) |
@Deprecated | 不鼓励使用该元素,通常是因为它很危险或存在更好的选择,编译器会发出警告 | @Target(value={ CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE }) |
@Suppress Warnings | 指示应该在注解元素(以及包含在该注解元素中的所有程序元素,例如注解一个类,则该类中的成员属性,方法等都会被注解)中取消显示指定的编译器警告,在给定元素中取消显示的警告集是所有包含元素中取消显示的警告的超集 | @Target(value={ TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE }) |
@SafeVarargs | 声明被注解的方法或构造器不能对其可变参数进行潜在的不安全的操作 | @Target(value={CONSTRUCTOR,METHOD}) |
@FunctionalInterface | 表明一个接口类型声明是Java语言规范定义的函数式接口 | @Target(value=TYPE) |
Java元注解
枚举RetentionPolicy可选值 | 作用范围 |
---|
SOURCE | 注解仅存在于源码中,在class字节码文件中不存在,注解将被编译器丢弃 |
CLASS | 默认的保存策略,注解会在class字节码文件中存在,但会被VM丢弃,运行时无法获取 |
RUNTIME | 注解会在class字节码文件中存在,且在VM运行期保留注解,可以通过反射机制获取注解信息(元注解的作用级别都是RUNTIME) |
枚举ElementType可选值 | 作用目标 |
---|
TYPE | 接口(包括注解类型)、类、枚举 |
FIFLD | 域声明(包括枚举实例) |
METHOD | 方法 |
PARAMETER | 方法参数 |
CONSTRUCTOR | 构造函数 |
LOCAL_VARIABLE | 局部变量 |
ANNOTATION_TYPE | 注解(元注解的作用目标都是ANNOTATION_TYPE) |
PACKAGE | 包 |
- @Inherited – 说明允许子类可以继承父类中的注解
- @Document – 说明该注解包含在Javadoc中
- @Repeatable – 说明该(元)注解是可重复注解的,即可以在相同的地方应用多次(since 1.8)
注解元素
- 类型限制
- 所有基本类型(boolean(1), byte(8), char(16), short(16), int(32), float(32), long(64), double(64))
- String
- Class
- enum
- Annotation (说明注解可以嵌套)
- 以上类型的数组
(如果使用其他类型,编译器会报错;理论上也不允许使用任何包装器类型,但是由于自动包装机制,如果使用包装器类型则会转型(拆箱)为对应的基本类型)
- 默认值限制
- 元素必须要么具有默认值,要么在使用注解时提供元素的值(元素不能有不确定的值)
- 对于非基本类型的元素,无论是在源代码中声明时,或是在注解接口中定义默认值时,都不能以null作为其值。(这个约束使得处理器很难表现一个元素的存在或缺失的状态,只能通过自定义一些特殊值,例如空字符串或负数,表示某个元素不存在)
- 快捷方式
- 注解中定义了名为value的元素,在应用该注解的时候如果该元素是唯一需要赋值的一个元素,那么此时无需使用名-值对的这种语法,而只需在括号内给出value元素所需的值即可
@Target(ElementType.METHIOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Example {
public int value();
public String others() default "";
}
public class Demo {
private int id = 1;
@Example(1)
public int getId() {
return id;
}ouhe
}
自定义注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Example {
String name();
String parameters() default "";
int type() default 1;
String typeName() default "output";
}
public class TestExample {
@Example(name = "sayHello")
public void sayHello() {
System.out.println("Hello");
}
}
public class ShowExample {
public static void main(String[] args) {
Class<TestExample> c = TestExample.class;
Method[] methods = c.getMethods();
for (Method m : methods) {
Example e = m.getAnnotation(Example.class);
if (e == null) {ouhe
System.out.println("-> " + m.getName());
} else {
System.out.println(">> " + e.name() + " : " + e.parameters() + ", " + e.type() + ":" + e.typeName());
}
}
}
}
>> sayHello : , 1:output
-> wait
-> wait
-> wait
-> equals
-> toString
-> hashCode
-> getClass
-> notify
-> notifyAll
- 使用场景
- 每当创建描述符性质的类或接口时,一旦包含了重复性的工作,那就可以考虑使用注解来简化和自动化该过程
注解与注释对比
- 注解是在实际的员代码级别保存所有的信息,而不是某种注释性的文字,这使得代码更整洁,且便于维护
- 如果没有用来读取注解的工具,那注解也不会比注释更有用
- 注解绝对更适合用于描述类相关的信息
补充
- 没有元素的注解称为标记注解,例如,@Native(since 1.8)
@Documented
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.SOURCE)
public @interface Native {
}
- 与其他任何Java接口一样,注解也将会编译成class文件
- 注解不支持继承,注解不能使用关键字extends来继承某个@interface