注解与反射

注解与反射

注解简单介绍

注解的基本结构

Java注解是附加在代码中的一些元信息,用于一些工具在编译、运行时进行解析和使用,起到说明、配置的功能。注解不会也不能影响代码的实际逻辑,仅仅起到辅助性的作用。包含在 java.lang.annotation 包中。

注解的基本方式如下 @An(value1 = “”, value2 = “” …);

需要注意的是,如果注解内不需要填写属性值 @An() 和 @An 等价

与注释不同,注释是会被编译器绝对忽视的,而注解根据作用范围的不同可以在程序的不同阶段起作用。

自定义注解

元注解

​ 元注解就是解释注解的注解,它注解的对象是前面介绍的注解

四种元注解:

Retention:指定注解的作用范围,三种 SOURCE,CLASS,RUNTIME
Target:指定注解可以在哪些地方使用
Documented :指定该注解是否会在 javadoc 体现
Inherited:子类会继承父类注解

Retention

​ 只能用于修饰一个 Annotation 定义, 用于指定该 Annotation 可以保留多长时间,@Rentention 包含一个 RetentionPolicy 类型的成员变量, 使用 @Rentention 时必须为该 value 成员变量指定值(值有三种)。

RetentionPolicy.SOURCE: 编译器使用后,直接丢弃这种策略的注释。

RetentionPolicy.CLASS: 编译器将把注解记录在 class 文件中 . 当运行 Java 程序时 , JVM 不会保留注解。 这是默认值。

RetentionPolicy.RUNTIME: 编译器将把注解记录在 class 文件中 . 当运行 Java 程序时 , JVM 会保留注解 . 程序可以 通过反射获取该注解。

Target

用于修饰 Annotation 定义,指定被修饰的 Annotation 能用于修饰哪些程序元素。@Target 也包含一个名为 value 的成员变量。取值如下:

public enum ElementType {
    /** Class, interface (including annotation type), or enum declaration */
    TYPE,

    /** Field declaration (includes enum constants) */
    FIELD,

    /** Method declaration */
    METHOD,

    /** Formal parameter declaration */
    PARAMETER,

    /** Constructor declaration */
    CONSTRUCTOR,

    /** Local variable declaration */
    LOCAL_VARIABLE,

    /** Annotation type declaration */
    ANNOTATION_TYPE,

    /** Package declaration */
    PACKAGE,

    /**
     * Type parameter declaration
     *
     * @since 1.8
     */
    TYPE_PARAMETER,

    /**
     * Use of a type
     *
     * @since 1.8
     */
    TYPE_USE
}
如何自定义注解并使用
/**
用于指定被修饰的 Annotation 能用于修饰哪些程序元素
*/
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE,TYPE_PARAMETER,TYPE_USE})
//指定生命周期
@Retention(RetentionPolicy.SOURCE)
public @interface MyAnnotation {
/**
1.使用default关键字初始化参数配置值
2.如果只有一个参数配置,建议参数配置名称使用value,这样在使用时可以不使用变量名
*/
	String value()  default "test";
}
复用注解

在默认情况下,一个类/变量/…上只能使用一个同名注解,若需要在同一个对象上使用复数个注解,可以通过以下方式来实现

1.JAVA8之后的版本可以通过新建一个注解来实现

/**
此处范围需要大于需要可以复数使用的注解范围
*/
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE,TYPE_PARAMETER,TYPE_USE})
@Retention(RetentionPolicy.SOURCE)
public @interface MyAnnotations {
/**
1.使用default关键字初始化参数配置值
2.如果只有一个参数配置,建议参数配置名称使用value,这样在使用时可以不使用变量名
*/
	MyAnnotation[]  value;
}


/**
用于指定被修饰的 Annotation 能用于修饰哪些程序元素
*/
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE,TYPE_PARAMETER,TYPE_USE})
//指定生命周期
@Retention(RetentionPolicy.SOURCE)
@Repeatable(RobotCommands.class)
public @interface MyAnnotation {
/**
1.使用default关键字初始化参数配置值
2.如果只有一个参数配置,建议参数配置名称使用value,这样在使用时可以不使用变量名
*/
	String value()  default "test";
}

这样就可以在同一个对象上多次使用MyAnnotation了。

需要注意的是,当对象上有多个MyAnnotation时,使用反射读取到的注解是MyAnnotations([MyAnnotation,MyAnnotation,……]);若只有一个MyAnnotation,则反射读取到的是MyAnnotation。如下所示:

//定义注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Repeatable(MyAnnotations.class)
public @interface MyAnnotation {
    String value();
}

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyAnnotations {
    MyAnnotation[] value();
}
package ASP;

//使用注解
public class testASP {

    @MyAnnotation("testA - 1")
    public void TestA() {
    }

    @MyAnnotation("testB - 1")
    @MyAnnotation("testB - 2")
    public void TestB() {
    }

}
//通过反射获取注解信息
public static void main(String[] args) throws ClassNotFoundException {
    Class<?> clazz = Class.forName("ASP.testASP");

    Map<String, List<String>> map1 = new HashMap<>();
    Map<String, String> map2 = new HashMap<>();
    //用getDeclaredMethods可以只取到声明的函数,引用的函数不被包含(比如说String啥的
    Method[] methodList = clazz.getDeclaredMethods();
    for (Method method : methodList) {
        //Command command = method.getAnnotation(Command.class);
        java.lang.annotation.Annotation[] annotates = method.getAnnotations();
        for (java.lang.annotation.Annotation annotation : annotates) {
            if (annotation instanceof MyAnnotations) {
                java.lang.annotation.Annotation[] annotations = ((MyAnnotations) annotation).value();
                for (Annotation annotations1 : annotations) {
                    MyAnnotation annotation1 = (MyAnnotation) annotations1;
                    System.out.println("MyAnnotations - " + annotation1.value());
                }
            }
            if (annotation instanceof MyAnnotation) {
                MyAnnotation annotation2 = method.getAnnotation(MyAnnotation.class);
                System.out.println("MyAnnotation - " + annotation2.value());
            }

        }
    }

}

MyAnnotations - testB - 1
MyAnnotations - testB - 2
MyAnnotation - testA - 1

最终结果如上所示,在使用反射时需要注意分别处理。

JAVA8之前我们也可以通过容器的写法达到类似的效果,如下:

@TestRepeatables({
    @TestRepeatable(name = "test1"),
    @TestRepeatable(name = "test2")}
    )
public class TestAnnotation1 {
}

反射简单介绍

反射是什么

Reflection(反射)是Java被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。

Class c = Class.forName("java.lang.Stirng")

加载完类之后,在堆内存的方法区中就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象就包含了完整的类的结构信息。

反射能做到什么

反射提供的功能:

  • 在运行时判断任意一个对象所属的类
  • 在运行时构造任意一个类的对象
  • 在运行时判断任意一个类所具有的成员变量和方法
  • 在运行时获取泛型信息
  • 在运行时调用任意一个对象的成员变量和方法
  • 在运行时处理注解
  • 生成动态代理

优点:可以实现动态创建和编译,体现出很大的灵活性

缺点:对性能有影响。使用反射基本上是一种解释操作,我们可以告诉JVM,我们希望做什么并且它满足我们的要求。这样总是慢于直接执行相同的操作

反射和注解相结合

注解只是程序的附加信息,但是加上反射,我们就可以获取这部分信息,并动态地运行特殊的逻辑。例如我们可以通过反射和注解的方式将某些信息,比如方法的名字和具体描述绑定在方法上,并对这些信息进行收集和统一处理。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DZC2fn7P-1678933383325)(C:\Users\linqiang11\AppData\Roaming\Typora\typora-user-images\image-20230316093855034.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iIeuJCeZ-1678933383329)(C:\Users\linqiang11\AppData\Roaming\Typora\typora-user-images\image-20230316093826676.png)]

如上所示,如果我们需要记录并统计某些方法的数量及某些信息,就可以在方法上加入注解描述,再通过反射获取。这样一来,后续方法的拓展性就得到增强,只需要在方法上规范加入注解就可以自动拓展,而不需要额外在另外的地方加入信息,保证了可拓展性。

在具体的项目上,我们也可以结合注解,让方法根据需求运行于不同的环境中,可以自由控制方法的作用范围。

一处理。


在这里插入图片描述

如上所示,如果我们需要记录并统计某些方法的数量及某些信息,就可以在方法上加入注解描述,再通过反射获取。这样一来,后续方法的拓展性就得到增强,只需要在方法上规范加入注解就可以自动拓展,而不需要额外在另外的地方加入信息,保证了可拓展性。

在具体的项目上,我们也可以结合注解,让方法根据需求运行于不同的环境中,可以自由控制方法的作用范围。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值