注解提供有关于程序但不属于程序本身的数据,注解对它们注解的代码的操作没有直接影响
一般的,我们定义自定义注解时,需要指定的元注解有两个:
@Target
注解标记另一个注解,以限制可以应用注解的Java元素类型。目标注解指定以下元素类型之一作为其值。
ElementType.ANNOTATION_TYPE 应用于注解类型
ElementType.CONSTRUCTOR 应用于构造函数
ElementType.FIELD 应用于属性
ElementType.LOCAL_VERIABLE 应用于局部变量
ElementType.METHOD 应用于方法级注解
ElementType.PACKAGE 应用于包申明
ElementType.PARAMETER 应用于方法的参数
ElementType.TYPE 应用于类的任何元素
@Retention
注解指定标记注解的存储方式
RetentionPolicy.SOURCE 标记的注解仅保留再源码级别中,并被编译器忽略
RetentionPolicy.CLASS 标记的注解在编译时由编译器保留,但Java虚拟机会忽略
RetentionPolicy.RUNTIME 标记的注解由JVM保留,因此运行时环境可以使用它
三个值中SOURCE<CLASS <RUNTIME ,即CLASS包含了SOURCE,RUNTIME包含了CLASS
注解的应用场景
SOURCE级别:源码级别的注解,可以提供给IDE语法检查、APT等场景,其在编译之后的class中被丢弃,其可以取代枚举,实现方法入参的限制
java中的枚举实质是特殊的单例的静态成员变量,在运行期所有枚举类作为单例全部加载到内存中,比常量多5到10倍的内存占用。
CLASS级别:定义位CLASS的注解会保留在class文件中,但是会被虚拟机忽略(即无法在运行期间反射获取注解)。此时完全符合此种注解的应用场景位字节码插装和热修复。
RUNTIME级别:使用场景是在程序运行期间使用反射
反射泛型的擦除
泛型擦除总结:
Java泛型擦除后可以通过反射添加元素,不过最好不要这么做,会有类型转换异常的风险。
泛型擦除后,类,字段和方法的形参泛型信息是会保存到Signature中的,另外可以通过匿名内部类的方式获取泛型的实参类型,比如Gson中的使用。
WS总结:
1.泛型会在编译的时候被擦除为Object
2.泛型类型只会在类,字段,以及方法形参保存泛型信息,正是因为有了Signature对泛型信息的保存,我们才能获取他们
3.实参是没有保存泛型信息,比如我们要进行序列化和反序列化的话,获取不到泛型信息的话,就很难进行序列化和反序列化了,这个时候我们可以参考Gson的解决方案,使用TypeToken匿名内部类的方式来保存泛型信息(根据第二点,类、字段和方法形参保存有泛型信息)。