java-注解与反射

一、注解定义

二、元注解

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

猜你喜欢

转载自blog.csdn.net/makeliwei1/article/details/81703840