Java注解
0.参考
1.注解的定义
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE,ElementType.METHOD})
public @interface TestAnnotation {
String type() default "";
}
2.元注解
元注解顾名思义我们可以理解为注解的注解,它是作用在注解中,方便我们使用注解实现想要的功能。它是Java提供的用来定义其他注解的注解。元注解分别有@Retention、 @Target、 @Document、 @Inherited和@Repeatable(JDK1.8加入)五种。
2.1 @Retention
Retention英文意思有保留、保持的意思,它表示注解存在阶段是保留在源码(编译期),字节码(类加载)或者运行期(JVM中运行)。在@Retention注解中使用枚举RetentionPolicy来表示注解保留时期。
- @Retention(RetentionPolicy.SOURCE),注解仅存在于源码中,在class字节码文件中不包含
- @Retention(RetentionPolicy.CLASS), 默认的保留策略,注解会在class字节码文件中存在,但运行时无法获得
- @Retention(RetentionPolicy.RUNTIME), 注解会在class字节码文件中存在,在运行时可以通过反射获取到
如果我们是自定义注解,则通过前面分析,我们自定义注解如果只存着源码中或者字节码文件中就无法发挥作用,而在运行期间能获取到注解才能实现我们目的,所以自定义注解中肯定是使用 @Retention(RetentionPolicy.RUNTIME)
@Retention(RetentionPolicy.RUNTIME) //运行时可检测到
public @interface TestAnnotation {
}
2.2 @Target
Target的英文意思是目标,这也很容易理解,使用@Target元注解表示我们的注解作用的范围就比较具体了,可以是类,方法,方法参数变量等,同样也是通过枚举类ElementType表达作用类型
- @Target(ElementType.TYPE) 作用接口、类、枚举、注解
- @Target(ElementType.FIELD) 作用属性字段、枚举的常量
- @Target(ElementType.METHOD) 作用方
- @Target(ElementType.PARAMETER) 作用方法参数
- @Target(ElementType.CONSTRUCTOR) 作用构造函数
- @Target(ElementType.LOCAL_VARIABLE)作用局部变量
- @Target(ElementType.ANNOTATION_TYPE)作用于注解(@Retention注解中就使用该属性)
- @Target(ElementType.PACKAGE) 作用于包
- @Target(ElementType.TYPE_PARAMETER) 作用于类型泛型,即泛型方法、泛型类、泛型接口
- @Target(ElementType.TYPE_USE) 类型使用.可以用于标注任意类型除了 class
一般比较常用的是ElementType.TYPE类型
2.3 @Documented
Document的英文意思是文档。它的作用是能够将注解中的元素包含到 Javadoc 中去。
2.4 @Inherited
Inherited的英文意思是继承,但是这个继承和我们平时理解的继承大同小异,一个被@Inherited注解了的注解修饰了一个父类,则它的子类也继承了父类的注解。
//自定义注解
@Inherited
@Documented
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface TestAnnotation {
String type() default "";
}
//父类
@TestAnnotation(type = "animal")
public class Animal {
}
//子类
public class Panda extends Animal{
public String name = "panda";
}
//控制台运行
public class Console {
public static void main(String[] args) {
//获取所有注解
Annotation[] annotations = Panda.class.getAnnotations();
for (int i = 0; i < annotations.length; i++) {
//打印输出子类的注解
System.out.println(annotations[i].toString());
}
}
}
结果
2.5 @Repeatable
Repeatable的英文意思是可重复的。顾名思义说明被这个元注解修饰的注解可以同时作用一个对象多次,但是每次作用注解又可以代表不同的含义。
//容器注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Fruits {
Apple[] value() ;
}
//具体注解
@Repeatable(value = Fruits.class)
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Apple {
double price();
}
//被注解类
@Apple(price = 2.0)
@Apple(price = 3.0)
public class Businessman {
}
//运行
public class Console {
public static void main(String[] args) {
Annotation[] annotations = Businessman.class.getAnnotations();
Fruits fruits = (Fruits)annotations[0];
for (Apple a:fruits.value()) {
System.out.println("价格="+a.price());
}
}
}
//结果
价格=2.0
价格=3.0
注:
- @Repeatable必须用两个注解来搭配使用
- 容器注解必须定义一个具体注解的属性,属性名必须是value。相当于把具体注解保存到容器注解的value数组中
3.注解的属性
注解的属性其实和类中定义的变量有异曲同工之处,只是注解中的变量都是成员变量(属性),并且注解中是没有方法的,只有成员变量,变量名就是使用注解括号中对应的参数名,变量返回值就是注解括号中对应参数值。可使用defalue来定义默认值
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Controller {
/**
* The value may indicate a suggestion for a logical component name,
* to be turned into a Spring bean in case of an autodetected component.
* @return the suggested component name, if any (or empty String otherwise)
*/
@AliasFor(annotation = Component.class)
String value() default "";
}
4.注解的本质
注解的本质就是一个Annotation接口
/**Annotation接口源码*/
public interface Annotation {
boolean equals(Object obj);
int hashCode();
Class<? extends Annotation> annotationType();
}
5.注解使用时的常用方法
- Class.getAnnotations() 获取所有的注解,包括自己声明的以及继承的
- Class.getAnnotation(Class< A > annotationClass) 获取指定的注解,该注解可以是自己声明的,也可以是继承的
- Class.getDeclaredAnnotations() 获取自己声明的注解
- Class.isAnnotationPresent(Class< A > annotationClass) 判断是否有某个注解
方法,属性,构造器,类都可以使用上面的方法。
public class Console {
public static void main(@RequestParam String[] args) throws NoSuchFieldException, NoSuchMethodException {
System.out.print("获取类上面的所有注解:");
Annotation[] annotations = Businessman.class.getAnnotations();
for (int i = 0; i < annotations.length; i++) {
System.out.println(annotations[i].annotationType());
}
Class<Businessman> clazz = Businessman.class;
System.out.println("判断类上的是否注解:"+clazz.isAnnotationPresent(Apple.class));
Field name = clazz.getField("Name");
System.out.println("判断属性上的是否注解:"+name.isAnnotationPresent(Fruits.class));
Method sell = clazz.getMethod("sell");
System.out.println("判断方法上的是否注解:"+sell.isAnnotationPresent(Fruits.class));
boolean hasAnnotation = clazz.isAnnotationPresent(Apple.class);
if(hasAnnotation){
Apple annotation = clazz.getAnnotation(Apple.class);
System.out.println("注解上面的值:"+annotation.price());
}
}
}
//输出
获取类上面的所有注解:interface com.meng.daily.basejava.annotation.Apple
判断类上的是否注解:true
判断属性上的是否注解:false
判断方法上的是否注解:false
注解上面的值2.0
在spring中可以使用AnnotationUtils工具类来进行操作