摘要:注解的定义注解通过关键字进行定义它的形式跟接口很类似,不过前面多了一个符号上面的代码就创建了一个名字为的注解你可以简单理解为创建了一张名字为的标签注解的应用上面创建了一个注解那么注解的的使用方法是什么呢创建一个类然后在类定义的地方加上就可以
java jdk: 10.0.2注解的定义
注解通过 @interface 关键字进行定义.
public @interface TestAnnotation { }
它的形式跟接口很类似,不过前面多了一个 @ 符号. 上面的代码就创建了一个名字为 TestAnnotaion 的注解.
你可以简单理解为创建了一张名字为 TestAnnotation 的标签.
注解的应用上面创建了一个注解, 那么注解的的使用方法是什么呢.
@TestAnnotation public class Test { }
创建一个类 Test, 然后在类定义的地方加上 @TestAnnotation 就可以用 TestAnnotation 注解这个类了.
你可以简单理解为将 TestAnnotation 这张标签贴到 Test 这个类上面.
不过, 要想注解能够正常工作, 还需要介绍一下一个新的概念那就是元注解.
元注解元注解是什么意思呢?
元注解是可以注解到注解上的注解, 或者说元注解是一种基本注解, 但是它能够应用到其它的注解上面.
如果难于理解的话, 你可以这样理解. 元注解也是一张标签, 但是它是一张特殊的标签, 它的作用和目的就是给其他普通的标签进行解释说明的.
元标签有 @Retention、 @Documented、@Target、 @Inherited、 @Repeatable 5 种.
@RetentionRetention 的英文意为保留期的意思. 当 @Retention 应用到一个注解上的时候, 它解释说明了这个注解的的存活时间.
它的取值如下:
RetentionPolicy.SOURCE 注解只在源码阶段保留, 在编译器进行编译时它将被丢弃忽视.
RetentionPolicy.CLASS 注解只被保留到编译进行的时候, 它并不会被加载到 JVM 中.
RetentionPolicy.RUNTIME 注解可以保留到程序运行的时候, 它会被加载进入到 JVM 中, 所以在程序运行时可以获取到它们.
我们可以这样的方式来加深理解, @Retention 去给一张标签解释的时候, 它指定了这张标签张贴的时间.
@Retention 相当于给一张标签上面盖了一张时间戳, 时间戳指明了标签张贴的时间周期.
@Retention(RetentionPolicy.RUNTIME) public @interface TestAnnotation { }
上面的代码中, 我们指定 TestAnnotation 可以在程序运行周期被获取到, 因此它的生命周期非常的长.
@Documented顾名思义, 这个元注解肯定是和文档有关. 它的作用是能够将注解中的元素包含到 Javadoc 中去.
@TargetTarget 是目标的意思, @Target 指定了注解运用的地方.
你可以这样理解, 当一个注解被 @Target 注解时, 这个注解就被限定了运用的场景.
ElementType.ANNOTATION_TYPE 可以给一个注解进行注解
ElementType.CONSTRUCTOR 可以给构造方法进行注解
ElementType.FIELD 可以给属性(字段)进行注解
ElementType.LOCAL_VARIABLE 可以给局部变量进行注解
ElementType.METHOD 可以给方法进行注解
ElementType.PACKAGE 可以给一个包进行注解
ElementType.PARAMETER 可以给一个方法内的参数进行注解
ElementType.TYPE 可以给一个类型进行注解, 比如类、接口、枚举
@InheritedInherited 是继承的意思, 但是它并不是说注解本身可以继承, 而是说如果一个超类被 @Inherited 注解过的注解进行注解的话, 那么如果它的子类没有被任何注解应用的话, 那么这个子类就继承了超类的注解.
说的比较抽象. 代码来解释.
@Inherited @Retention(RetentionPolicy.RUNTIME) @interface Test {} @Test public class A {} public class B extends A {}
注解 Test 被 @Inherited 修饰, 之后类 A 被 Test 注解, 类 B 继承 A, 类 B 也拥有 Test 这个注解.
@RepeatableRepeatable 自然是可重复的意思.
什么样的注解会多次应用呢? 通常是注解的值可以同时取多个.
举个例子, 一个人他既是程序员又是产品经理, 同时他还是个画家.
@interface Persons { Person[] value(); } @Repeatable(Persons.class) @interface Person{ String role default ""; } @Person(role="artist") @Person(role="coder") @Person(role="PM") public class SuperMan{ }
注意上面的代码, @Repeatable 注解了 Person. 而 @Repeatable 后面括号中的类相当于一个容器注解.
什么是容器注解呢? 就是用来存放其它注解的地方. 它本身也是一个注解.
我们再看看代码中的相关容器注解.
@interface Persons { Person[] value(); }
按照规定, 它里面必须要有一个 value 的属性, 属性类型是一个被 @Repeatable 注解过的注解数组, 注意它是数组.
注解的属性@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface TestAnnotation { int id(); String msg(); }
上面代码定义了 TestAnnotation 这个注解中拥有 id 和 msg 两个属性. 在使用的时候, 我们应该给它们进行赋值.
赋值的方式是在注解的括号内以 value=”” 形式, 多个属性之前用 , 隔开.
@TestAnnotation(id=3,msg="hello annotation") public class Test { }
⚠️ 在注解中定义属性时它的类型必须是 8 种基本数据类型外加 类、接口、注解及它们的数组.判断类上是否使用指定注解
Map判断字段上是否使用指定注解> stringClassMap = ClassUtil.getClasses("org.itzhizhe.testReflection"); stringClassMap.forEach((key, value) ->{ ReflectionClass annotation = value.getAnnotation(ReflectionClass.class); if (annotation != null) { System.out.println("class name: " + value.getSimpleName() + ", 注解 value : " + annotation.Value()); } });
Map判断方法上是否使用指定注解> stringClassMap = ClassUtil.getClasses("org.itzhizhe.testReflection"); stringClassMap.forEach((key, value) -> { for (Field declaredField : ClassUtil.getAnnotatedDeclaredFields(value, ReflectionField.class, false)) { ReflectionField annotation = declaredField.getAnnotation(ReflectionField.class); if (annotation != null) { this.put(annotation.Value(), declaredField); System.out.println("class name: " + value.getSimpleName() + ", 字段名: " + declaredField.getName() + ", 字段类型:" + declaredField.getType().getSimpleName() + ", 注解值:" + annotation.Value() ); } } });
Map创建对象> stringClassMap = ClassUtil.getClasses("org.itzhizhe.testReflection"); stringClassMap.forEach((key, value) -> { for (Method declaredField : ClassUtil.getAnnotatedDeclaredMethods(value, ReflectionMethod.class,false)) { ReflectionMethod annotation = declaredField.getAnnotation(ReflectionMethod.class); if (annotation != null) { System.out.println("class name: " + value.getSimpleName() + ", 方法名: " + declaredField.getName() + ", 方法返回类型:" + declaredField.getReturnType() + ", 注解值:" + annotation.id() ); } } });
value.getConstructor().newInstance();
上面代码是使用无参构造来创建对象, 当然也可以使用有参构造来创建对象.
getConstructor() 参数填写构造参数的参数类型.
newInstance() 参数填写传给构造参数的值.
调用方法可以通过 Method 的 setAccessible 方法设置为 true, 就可以调用对象的 private 方法.
declaredField.setAccessible(true); declaredField.invoke(value);
然后可以使用 invoke 方法来进行方法调用. 第一个参数为要调用方法的对象. 剩下的参数是方法参数.
总结如果想实现像 Spring 这种框架, 实现上面几步是必须.
比如依赖注入, 我们需要知道字段的类型, 然后到 IOC 容器中找到对应的对象进行赋值.
而方法调用你可以先将注解的方法进行保存, 比如保存到 Map 集合中.
例如客户端发送指定数据帧后, 然后通过 key 取出要执行的方法后执行就可以.
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/72326.html
摘要:反射机制一结合官方通过编写的反射教程,复习一下反射的知识。反射的概念反射是一种在运行时获取以及修改应用行为的一种工具。因为反射需要动态的解析类的信息,相比于非反射使用的方式要慢。反射需要获取一定的运行时权限,在特定的安全环境下不一定存在。 Java反射机制(一) 结合Oracle官方通过JDK8编写的反射教程,复习一下反射的知识。结尾篇补一个小例子。 主要内容 这次博客的主要内容就是简...
摘要:通过反射获取带参无返回值成员方法并使用设置安全检查,访问私有构造函数必须创建实例这种不行,注意和方法需要传递参数测试复制这个功能获取私有方法,同样注意和的区别赋予访问权限调用方法。 反射 目录介绍 1.反射概述 1.1 反射概述 1.2 获取class文件对象的三种方式 1.3 反射常用的方法介绍 1.4 反射的定义 1.5 反射的组成 1.6 反射的作用有哪些 2.反射的...
摘要:反射使用类对象提供的基本元数据,能从类对象中找出方法或字段的名称,然后获取表示方法或字段的对象。常见的反射手段有反射和反射。以之前的反射为例其中指定了方法的返回类型,其实不止如此。 Java反射机制主要提供了以下功能: 在运行时判断任意一个对象所属的类 在运行时构造任意一个类的对象 在运行时判断任意一个类所具有的成员变量和方法 在运行时调用任意一个对象的方法 生成动态代理 很多框架...
近期在维护公司项目的时候遇到一个问题,因为实体类中的 set 方法涉及到了业务逻辑,因此在给对象赋值的过程中不能够使用 set 方法,为了实现功能,所以采用了反射的机制给对象属性赋值,借此机会也了解了反射的一些具体用法和使用场景,分以下两点对反射进行分析: 反射的优势和劣势 反射的应用场景 反射的优势和劣势 个人理解,反射机制实际上就是上帝模式,如果说方法的调用是 Java 正确的打开方式...
摘要:一反射机制概念程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言,如,是动态语言显然,,不是动态语言,但是有着一个非常突出的动态相关机制。相关的为二获取源头重点打开权限所有类的对象其实都是的实例。 一、Java反射机制概念 程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言,如Python, Ruby是动态语言;显然C++,Java,C#不是动态语言,但是JAVA有...
阅读 1761·2021-11-24 09:39
阅读 1550·2021-11-16 11:54
阅读 3496·2021-11-11 16:55
阅读 1654·2021-10-14 09:43
阅读 1444·2019-08-30 15:55
阅读 1232·2019-08-30 15:54
阅读 3420·2019-08-30 15:53
阅读 1337·2019-08-30 14:18