Java注解基本介绍 二
为了处理上述的新增注解,Java8还在AnnotatedElement接口新增了getDeclaredAnnotationsByType() 和 getAnnotationsByType()两个方法并在接口给出了默认实现
在指定@Repeatable的注解时,可以通过这两个方法获取到注解相关信息。
这里我们需要注意的是旧版API中的getDeclaredAnnotation()和 getAnnotation()是不对@Repeatable注解的处理的(除非该注解没有在同一个声明上重复出现)。
注意getDeclaredAnnotationsByType方法获取到的注解不包括父类,其实当 getAnnotationsByType()方法调用时,其内部先执行了getDeclaredAnnotationsByType方法
只有当前类不存在指定注解时,getAnnotationsByType()才会继续从其父类寻找,但请注意如果@FilterPath和@FilterPaths没有使用了@Inherited的话,仍然无法获取。
下面是示例代码:
import java.lang.annotation.*;
@Target({ElementType.TYPE,ElementType.FIELD,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited //添加可继承元注解
@Repeatable(FilterPaths.class) // 参数指定接收的class
public @interface FilterPath{
String value();
}
@Target(ElementType.TYPE)
@Inherited //添加可继承元注解
@Retention(RetentionPolicy.RUNTIME)
@interface FilterPaths {
FilterPath[] value();
}
@FilterPath("/test1/1")
@FilterPath("/test1/2")
@FilterPath("/test1/3")
class Test1{ }
//只有在子类没有使用@FilterPath注解的时候,getAnnotationsByType()方法才会从父类中找@FilterPath,反之则不会
//@FilterPath("/test2/1")
//@FilterPath("/test2/2")
//@FilterPath("/test2/3")
class Test2 extends Test1 {
public static void main(String[] args) {
Class<?> clazz = Test2.class;
//通过getAnnotationsByType方法获取所有重复注解
FilterPath[] annotationsByType = clazz.getAnnotationsByType(FilterPath.class);
FilterPath[] annotationsByType2 = clazz.getDeclaredAnnotationsByType(FilterPath.class);
if (annotationsByType != null) {
for (FilterPath filter : annotationsByType) {
System.out.println("1:"+filter.value());
}
}
System.out.println("-----------------");
if (annotationsByType2 != null) {
for (FilterPath filter : annotationsByType2) {
System.out.println("2:"+filter.value());
}
}
System.out.println("使用getAnnotation的结果:"+clazz.getAnnotation(FilterPath.class));
}
}
/**
* 运行结果如下:
*
* 1:/test1/1
* 1:/test1/2
* 1:/test1/3
* -----------------
* 使用getAnnotation的结果:null
*/
Java 8 新增的注解类型
在Java 8中 ElementType 新增两个枚举成员,TYPE_PARAMETER 和 TYPE_USE ,在Java 8前注解只能标注在一个声明(如字段、类、方法)上,Java 8后,新增的TYPE_PARAMETER可以用于标注类型参数,而TYPE_USE则可以用于标注任意类型(不包括class)
如下所示
//TYPE_PARAMETER 标注在类型参数上
class D<@Parameter T> { }
//TYPE_USE则可以用于标注任意类型(不包括class)
//用于父类或者接口
class Image implements @Rectangular Shape { }
//用于构造函数
new @Path String("/usr/bin")
//用于强制转换和instanceof检查,注意这些注解中用于外部工具,它们不会对类型转换或者instanceof的检查行为带来任何影响。
String path=(@Path String)input; if(input instanceof @Path String)
//用于指定异常
public Person read() throws @Localized IOException.
//用于通配符绑定
List<@ReadOnly ? extends Person>
List<? extends @ReadOnly Person>
@NotNull String.class
//非法,不能标注
class import java.lang.@NotNull String
//非法,不能标注import
这里主要说明一下TYPE_USE,类型注解用来支持在Java的程序中做强类型检查,配合第三方插件工具,可以在编译期检测出runtime error(如UnsupportedOperationException、NullPointerException异常),避免异常延续到运行期才发现,从而提高代码质量,这就是类型注解的主要作用。
总结,Java 8中新增加了两个注解的元素类型ElementType.TYPE_USE 和ElementType.TYPE_PARAMETER ,通过它们,我们可以把注解应用到各种新场合中。
