Annotation
Annotation是一个接口,可以把Annotation当成一个修饰符
Annotation的定义
注解通过@interface定义
public @interface TestAnnotation {
//Annotation的成员变量通过无形参的方法形式声明,方法名和返回值表示成员变量的名字和类型
String name();
//默认值通过default指定
int age() default 32;
}
提取Annotation的信息
提取Annotation的信息需要用到java.lang.reflect的反射API,并且在定义Annotation的@Retention要指定为RetentionPolicy.RUNTIME
5个基本的Annotation
@Override->强制重写父类的方法,避免出现父类方法名和子类方法名不一致的错误
@Deprecated->标记方法已过时
@Suppress Warnings->取消编译器的警告
@Safe Varages->解决“堆污染”
public static void main(String[] args) { List list = new ArrayList(); list.add(20); //当把一个不带泛型的对象赋值给一个带泛型的变量,引发的错误叫“堆污染”,发生ClassCastException List<String> ls = list; System.out.println(ls.get(0)); }
@FunctionalInterface->标记接口是一个函数式接口
@FunctionalInterface //函数式接口中有一个抽象方法,多个静态方法和默认方法,如果试图声明第二个抽象方法,会报错 public interface Test { void a(); default void b(){ System.out.println("b"); } static void c() { System.out.println("c"); } }
6个Meta Annotation
@Retention
Retention用于修饰Annotation,作用是指定修饰的Annotation可以保留多长时间
//Retention有一个RetentionPolicy的成员变量value // value的取值:RetentionPolicy.RUNTIME,RetentionPolicy.CLASS,RetentionPolicy.SOURCE //RUNTIME、CLASS会将Annotation记录在class文件中,SOURCE会直接丢弃Annotation //RUNTIME可以通过反射获取Annotation的信息,class不可以 @Retention(RetentionPolicy.RUNTIME) public @interface Test { }
@Target
Target用于修饰Annotation,作用是指定Annotation可以修饰那些程序单元
- ElementType.ANNOTATION_TYPE 可以给一个注解进行注解
- ElementType.CONSTRUCTOR 可以给构造方法进行注解
- ElementType.FIELD 可以给属性进行注解
- ElementType.LOCAL_VARIABLE 可以给局部变量进行注解
- ElementType.METHOD 可以给方法进行注解
- ElementType.PACKAGE 可以给一个包进行注解
- ElementType.PARAMETER 可以给一个方法内的参数进行注解
- ElementType.TYPE 可以给一个类型进行注解,比如类、接口、枚举
//Retention有一个ElementType的成员变量value @Target(ElementType.FIELD) public @interface Test { }
class A{
@Test
private int a;
}
@Documented
Documented用于修饰Annotation,作用是指定被Documented修饰的Annotation类会被javadoc提取成文档
@Inherited
Inherited用于修饰Annotation,作用是指定被修饰的Annotation具有继承性
@Inherited //注意这要写上RUNTIME,不然下边的isAnnotationPresent()不能通过反射拿到Annotation信息 @Retention(RetentionPolicy.RUNTIME) public @interface Test { } @Test class A{ } //B类并未使用@Test注解,但是B类也被@Test修饰了 class B extends A{ public static void main(String[] args){ System.out.println(B.class.isAnnotationPresent(Test.class)); } }
@Repeatable
Repeatable用于修饰Annotation,可以使用多个相同名字的注解
//在没有使用Repeatable前,我们要给某个程序元素注解多个相同名字的注解时,必须要有一个容器注解 @Retention(RetentionPolicy.RUNTIME) public @interface Result{ String name(); int age(); } @Retention(RetentionPolicy.RUNTIME) @interface Results{ Result[] value(); } @Results({@Result(name="张三",age=16), @Result(name="李四",age=20)} ) class Person{ public static void main(String[] args){ Class<Person> pClass = Person.class; Results results = pClass.getDeclaredAnnotation(Results.class); System.out.println(results); } }
//使用Repeatable注解修改 @Retention(RetentionPolicy.RUNTIME) @Repeatable(Results.class) public @interface Result{ String name(); int age(); } @Retention(RetentionPolicy.RUNTIME) @interface Results{ Result[] value(); } @Result(name="张三",age=16) @Result(name="李四",age=20) class Person{ public static void main(String[] args){ Class<Person> pClass = Person.class; Results results = pClass.getDeclaredAnnotation(Results.class); System.out.println(results); } }
实际上任然需要容器注解,只是红色的部分写法发生了变化
ElemType
Java 8 中 ElementType 增加了 ElementType.TYPE_USE 和 ElementType.TYPE_PARAMETER。它们都可以限制哪个类型可以进行注解。能在局部变量、泛型类、父类和接口的实现处使用,甚至能在方法上声明异常的地方使用。
ElementType.TYPE_PARAMETER(Type parameter declaration) 用来标注类型参数。
@Target(ElementType.TYPE_PARAMETER) @Retention(RetentionPolicy.RUNTIME) public @interface TypeParameterAnnotation { } // 如下是该注解的使用例子 public class TypeParameterClass<@TypeParameterAnnotation T> { public <@TypeParameterAnnotation U> T foo(T t) { return null; } }
ElementType.TYPE_USE(Use of a type) 能标注任何类型名称,包括上面这个(ElementType.TYPE_PARAMETER的)
ublic class TestTypeUse { @Target(ElementType.TYPE_USE) @Retention(RetentionPolicy.RUNTIME) public @interface TypeUseAnnotation { } public static @TypeUseAnnotation class TypeUseClass<@TypeUseAnnotation T> extends @TypeUseAnnotation Object { public void foo(@TypeUseAnnotation T t) throws @TypeUseAnnotation Exception { } } // 如下注解的使用都是合法的 @SuppressWarnings({ "rawtypes", "unused", "resource" }) public static void main(String[] args) throws Exception { TypeUseClass<@TypeUseAnnotation String> typeUseClass = new @TypeUseAnnotation TypeUseClass<>(); typeUseClass.foo(""); List<@TypeUseAnnotation Comparable> list1 = new ArrayList<>(); List<? extends Comparable> list2 = new ArrayList<@TypeUseAnnotation Comparable>(); @TypeUseAnnotation String text = (@TypeUseAnnotation String)new Object(); java.util. @TypeUseAnnotation Scanner console = new java.util.@TypeUseAnnotation Scanner(System.in); } }