一、注解定义
二、元注解
2.1、元注解定义
当我们自定义一个注解时,我们可以在自定义注解上添加元注解;用一句更通俗的话来说就是我们可以在标签上再贴一个标签。
2.2、元注解种类
注解类型 | 方法描述 |
---|---|
@Retention | 指明这个注解的生命周期 |
@Target | 指明注解就运用的场景,如类、方法、构造器、域… |
@Inherited | 指明注解是否可继承 |
@Documnet | 指明javadoc需要包含注解信息 |
@Repeatable | 指明注解作为一个容器 |
@Retention
当@Retention注解到一个注解上时,可以指明这个注解的生命周期
value | 功能描述 |
---|---|
RetentionPolicy.SOURCE | 注解只在源码阶段保留,在编译阶段被丢弃 |
RetentionPolicy.CLASS | 注解会被编译到.class二进制文件中,但是不会加载到JVM当中 |
RetentionPolicy.RUNTIME | 它会被加载到JVM当中,所以在程序运行可以通过反射的方式获取注解 |
对于RetentionPolicy.SOURCE和RetentionPolicy.CLASS我们不能通过反射机制获取,而RetentionPolicy.RUNTIME可以获取。
@Target
当一个注解被@Target注解时,这个注解就被限定了运用场景了,比如我们限定这个注解只能用在方法上,那么如果我们用在类上面,那么编译时期就会报错。
注解成员 | 功能描述 |
---|---|
ElementType.Annotation_TYPE | 可以给一个注解进行注解 |
ElementType.CONSTRUCTOR | 可以给构造方法进行注解 |
ElementType.FIELD | 可以给类的域进行注解 |
ElementType.LOCAL_VARIABLE | 可以个局部变量进行注解 |
ElementType.METHOD | 可以给方法进行注解 |
ElementType.PARAMETER | 可以给参数进行注解 |
ElementType.TYPE | 可以给一个类型进行注解 |
@Inherited
如果一个父类被@Inherited注解过的注解进行注解的话,那么如果有子类继承了这个父类,那么子类也会继承这个子类(这句话说起来有点拗口,就是如果我们在一个类上面添加了一个注解,而这个注解定义时添加了@Inherited,那么如果有一个子类继承了该类,那么这个子类也就拥有类父类的注解);
这个元注解使用在类注解上面才有用,对于方法上面的注解是无效的;需要注意的是,子类只会继承父类的在上面的注解并不会继承在方法上面的注解。
@Documnet
将我们的注解信息添加到javadoc中
@Repeatable
三、Java自带的注解
@Override
当一个子类继承父类并重写父类的方法时,此时就会在方法上就需要添加这个注解表示这个方法是重写的方法
@Deprecate
在JDK中如果一个方法添加了上面的这个
@Suppresswarning
四、自定义注解
3.1、定义注解
要素 | 解释 |
---|---|
关键字 | @interface表明这时一个注解 |
成员变量 | methodName()以无参、无异常的方式声明类似接口中的方法无方法主体 |
default | 为成员变量设置初始值 |
注意:
- 成员变量类型包括原始数据类型及String、Class、Annotation、Enumeration类型,否则编译时会报错
- 如果注解只有一个成员变量,那么成员名必须为value(),在使用时可以忽略成员名和赋值”=”。
- 注解类可以没有成员,没有成员的注解称为标识注解
@ClassDesc
是一个在类上面注解的信息
package AnnotationLearn;
import java.lang.annotation.*;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface ClassDesc {
String desc();
String classType() default "class";
}
@MethodDesc
是一个用在方法上的注解
package AnnotationLearn;
import java.lang.annotation.*;
@Target(ElementType.METHOD) //表明这个注解使用在方法上
@Retention(RetentionPolicy.RUNTIME) //表明这个注解在运行时可以通过反射的方式获取
@Inherited
public @interface MethodDesc {
String desc();
String returnType() default "void";
}
3.2 使用注解
写一个父类Father.java
package AnnotationLearn;
@ClassDesc(desc="这是一个父类")
public class Father {
@MethodDesc(desc="父类的方法")
public void driver(){
System.out.println("开车去上班");
}
}
Son.java 继承父类的信息
package AnnotationLearn;
public class Son extends Father{
@Override
public void driver() {
super.driver();
}
}
五、注解与反射
反射与注解主要涉及的几个方法
Class 中的获取类上面的注解方法,在Method和Field上面获取到的注解方法与次类似,此处只是列出了几个常用的方法。
方法名 | 返回值 | 描述 |
---|---|---|
Annotation[] | getDeclaredAnnotations() | |
Annotation[] | getAnnotations() | |
A extends Annotation | getAnnotation(Class annotationClass) |
测试类
package AnnotationLearn;
import org.junit.Test;
import java.lang.reflect.Method;
public class TestAnnotation {
@Test
public void testFather(){
//1、通过Class.forName加载了
try {
Class clazz = Class.forName("AnnotationLearn.Father");
//2、判断类上面是否存在注解
boolean isClassAnnotation = clazz.isAnnotationPresent(ClassDesc.class);
//3、获取类上面的Annotation
if(isClassAnnotation){
ClassDesc classDesc = (ClassDesc) clazz.getAnnotation(ClassDesc.class);
System.out.println("desc : "+classDesc.desc());
System.out.println("classType : "+classDesc.classType());
}
//1、通过反射获取方法
Method method = clazz.getDeclaredMethod("driver",null);
//2、判断这个注解是否存在
boolean isMethodAnnotation = method.isAnnotationPresent(MethodDesc.class);
if(isMethodAnnotation){
//3、获取注解
MethodDesc methodDesc = method.getAnnotation(MethodDesc.class);
System.out.println("desc : "+methodDesc.desc());
System.out.println("returnType : "+methodDesc.returnType());
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
@Test
public void testSon(){
//1、通过Class.forName加载了
try {
Class clazz = Class.forName("AnnotationLearn.Son");
//2、判断类上面是否存在注解
boolean isClassAnnotation = clazz.isAnnotationPresent(ClassDesc.class);
//3、获取类上面的Annotation
if(isClassAnnotation){
ClassDesc classDesc = (ClassDesc) clazz.getAnnotation(ClassDesc.class);
System.out.println("desc : "+classDesc.desc());
System.out.println("classType : "+classDesc.classType());
}
//1、获取方法
Method method = clazz.getDeclaredMethod("driver",null);
//2、判断这个注解是否在方法上
boolean isMethodAnnotation = method.isAnnotationPresent(MethodDesc.class);
if(isMethodAnnotation){
//3、获取方法上面的注解
MethodDesc methodDesc = method.getAnnotation(MethodDesc.class);
System.out.println("desc : "+methodDesc.desc());
System.out.println("returnType : "+methodDesc.returnType());
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
}
输出结果
//Test Father的输出结果
desc : 这是一个父类
classType : class
desc : 这是一个父类
classType : class
//Test Son 的输出结果
desc : 父类的方法
returnType : void
从上面结果我们也可以看到,因为对于@Inherited这个注解,当其注解@ClassDesc这个注解上,Son这个类也可以继承父类Father的类上面的注解。@Inherited注解在@MethodDesc这个注解上时,因为Son虽然重写了父类的方法,所以不会继承父类该方法的注解。
六、参考文章
https://blog.csdn.net/briblue/article/details/73824058#commentBox