Java内置注解
注解(annotation)自 Java 1.5 开始引入,也被称为元数据。
Java内置了几种注解(Java 注解深入理解)
- @Override:表示当前的方法定义将覆盖超类中的方法。注解目标为方法。源文件有效
- @Deprecated:表示已被弃用,将在未来的某个版本移除。注解目标为类、成员变量、方法、方法参数、构造函数、局部变量和包。运行期有效
- @SuppressWarnings:关闭编译器警告信息。注解目标为类、成员变量、方法、方法参数、构造函数和局部变量。源文件有效
- @SafeVarargs(java 1.7新增):参数安全类型注解。它的目的是提醒开发者不要用参数做一些不安全的操作,它的存在会阻止编译器产生 unchecked 这样的警告。注解目标为构造器和方法。运行期有效
- @FunctionalInterface(java 1.8新增):函数式接口注解。注解目标为类、接口(包括注解类型)或enum声明。运行期有效
自定义注解
除了内置注解外,Java我们通过四种元注解(meta-annotation)建立自己的注解。元注解的作用就是负责注解其他注解。
- @Target:表示注解可以用于什么地方。参数ElementType,包括:
- CONSTRUCTOR:构造器声明
- FIELD:域声明
- LOCAL_VARIABLE:局部变量声明
- METHOD:方法声明
- PACKAGE:包声明
- PARAMETER:参数声明
- TYPE:类、接口(包括注解类型)或enum声明
- TYPE_PARAMETER(java 1.8新增): 表示该注解能写在类型变量的声明语句中
- TYPE_USE(java 1.8新增):表示该注解能写在使用类型的任何语句中(例如声明语句、泛型和强制转换语句中的类型)
- @Retention:表示需要在什么级别保存该注解信息。参数RetentionPolicy,包括
- SOURCE:在源文件中有效(源文件保留)
- CLASS:在class文件中有效(class保留)
- RUNTIME:在运行时有效(运行时保留),可以通过反射机制读取注解的信息
- @Documented:将此注解包含在Javadoc中
- @Inherited:允许子类继承父类中的注解
- @Repeatable(java 1.8新增):可重复
当注解未指定Target值时,则此注解可以用于任何元素之上;如果一个注解要在运行时被成功提取,那么必须加上@Retention(RetentionPolicy.RUNTIME) 。
在实际应用中一般都会使用自己定义的注解。 适当的注解可以减少工作量,简化程序中的配置。提高效率。目前注解已经成为Spring开发的主流。
注解通过 @interface 关键字进行定义。
如下所示:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
}
注解的属性也叫做成员变量。注解的成员变量在注解的定义中以“无参方法”的形式声明,只能用public或默认访问权修饰,方法名为成员变量的名字,返回值为成员变量的类型。如果只有一个参数成员,最好把参数名称设为"value"。
属性可以有默认值,默认值需要用 default 关键值指定。
注意:对于非基本元素,不能以null作为其值
示例如下:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
int id() default -1;
String name() default "-1";
}
反射获取注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@interface methodAnnotation {
int id() default -1;
String name() default "null";
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@interface classAnnotation {
int id() default -1;
String name() default "null";
}
@classAnnotation
class Anno {
@methodAnnotation
public void f(String msg) {
System.out.println(msg);
}
}
@Deprecated
public class AnnotationDemo extends Anno {
@SuppressWarnings("unused")
private static int a = 1;
@Override
public void f(String msg) {
System.out.println(msg);
}
public static void main(String[] args) throws NoSuchMethodException, SecurityException {
Class<?> clazz = AnnotationDemo.class;
// 获取类的所有注解,包含父类注解
Annotation[] allInClass = clazz.getAnnotations();
System.out.println("类注解(含父类):" + Arrays.toString(allInClass));
// 获取类的所有注解,不包含父类注解
Annotation[] allExceptFather = clazz.getDeclaredAnnotations();
System.out.println("类注解(不含父类):" + Arrays.toString(allExceptFather));
// 获取成员变量注解
Field[] field = clazz.getDeclaredFields();
Annotation[] allInField = field[0].getAnnotations();
System.out.println("成员变量注解:" + Arrays.toString(allInField));
// 获取方法注解
Method[] method = clazz.getMethods();
Annotation[] allInMethod = method[1].getAnnotations();
System.out.println("方法注解:" + Arrays.toString(allInMethod));
// 判断是否有Deprecated注解
boolean specAnno = clazz.isAnnotationPresent(Deprecated.class);
System.out.println("是否有Deprecated注解:" + specAnno);
}
}
输出结果:
类注解(含父类):[@test.classAnnotation(name=null, id=-1), @java.lang.Deprecated()]
类注解(不含父类):[@java.lang.Deprecated()]
成员变量注解:[]
方法注解:[]
是否有Deprecated注解:true
可以看到,@Override与@SupressedWarnings因为是源文件有效而不能通过反射获取;getDeclaredAnnotations()方法不能获取父类注解。