我看JAVA 之 Annotation
我看JAVA 之 Annotation
注:基于jdk11
注解包结构
名词解释:
- meta-annotation 元数据注解 表示用来声明注解的注解
- marker-annotation 标记注解 表示没有成员的注解
Annotation
Annotation 是一个被所有注解类型实现的通用接口。但是如果硬编码实现此接口不能定义一个注解类型,同时,此接口本身也不是一个注解类型。 所有注解声明格式为: @interface annotationName{ } 隐式表明某个类型(注解类型)实现了接口java.lang.annotation.Annotation
public interface Annotation { boolean equals(Object obj); int hashCode(); String toString(); Class<? extends Annotation> annotationType(); }
Target
meta-annotation,表示某注解类型应用在哪些语法元素上,默认应用在除TYPE外的所有语法元素上。
@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Target { /** * Returns an array of the kinds of elements an annotation type * can be applied to. * @return an array of the kinds of elements an annotation type * can be applied to */ ElementType[] value(); }
ElementType
枚举类型 表示某注解可以应用的元素上下文。
public enum ElementType { TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE, ANNOTATION_TYPE, PACKAGE, /** * Type parameter declaration * @since 1.8 */ TYPE_PARAMETER, /** * Use of a type * @since 1.8 */ TYPE_USE, /** * Module declaration. * @since 9 */ MODULE }
Retention
meta-annotation 表示注解类型持有范围或生命周期。
@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Retention { /** * Returns the retention policy. * @return the retention policy */ RetentionPolicy value(); }
RetentionPolicy
枚举类型 表示持有注解周期策略。
public enum RetentionPolicy { SOURCE,//应用在源文件上,主要做编译时检查,检查完毕即丢弃。 CLASS,//默认值,被编译器记录在字节码文件中,但不能被运行时持有。 RUNTIME//除了可以被编译器记录在字节码文件中,还可以被运行时持有。参见:java.lang.reflect. AnnotatedElement(表示运行在VM的程序中的可以被注解或注解了的元素) }
Inherited
meta-annotation 同时也是marker-annotation 表示某个注解类型是可以被继承的
Documented
meta-annotation 同时也是marker-annotation 表示某个类型标记@Documented注解,那么此类型上所有注解会被JAVA Doc收集为API一部分
Native
meta-annotation 同时也是marker-annotation(since1.8),表明一个字段引用的值可能来自于本地代码
Repeatable
meta-annotation(since1.8)
异常
AnnotationFormatError
AnnotationTypeMismatchException
IncompleteAnnotationException
内部原理
以实现一个简单的orm注解的形式来描述Java的Annotation的内部原理,代码如下:
源代码
package chapter04; import java.lang.annotation.*; /** * a orm's table annotation */ @Documented @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface Table { String name() default ""; String alias() default ""; }
package chapter04; import java.lang.annotation.*; /** * a orm's column annotation */ @Documented @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface Column { boolean primary() default false; String name() default ""; String type() default "varchar"; int length() default 0; String alias() default ""; }
package chapter04; @Table(name = "t_student", alias = "s") public class Student { @Column(primary = true, name = "_id", type = "bigint", length = 20) String id; @Column(name = "name", type = "string", length = 32) String name; }
package chapter04; public class TestAnno { public static void main(String [] args) throws NoSuchFieldException { System.setProperty("jdk.proxy.ProxyGenerator.saveGeneratedFiles", "true"); Table table = Student.class.getAnnotation(Table.class); System.out.printf("table'name is %s, alias is %s. \n", table.name(), table.alias()); Column column = Student.class.getDeclaredField("id").getAnnotation(Column.class); System.out.printf("column'name is %s, alias is %s. \n", column.name(), column.alias()); } }
通过设置环境变量,可以保存jdk动态生成的代码,查看java.lang.reflect.ProxyGenerator类中的配置, 如下:
/** debugging flag for saving generated class files */ private static final boolean saveGeneratedFiles = java.security.AccessController.doPrivileged( new GetBooleanAction( "jdk.proxy.ProxyGenerator.saveGeneratedFiles")).booleanValue();
jdk生成的代理代码
package com.sun.proxy; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.lang.reflect.UndeclaredThrowableException; public final class $Proxy0 extends Proxy implements Retention { private static Method m1; private static Method m2; private static Method m4; private static Method m0; private static Method m3; public $Proxy0(InvocationHandler var1) throws { super(var1); } public final boolean equals(Object var1) throws { try { return (Boolean)super.h.invoke(this, m1, new Object[]{var1}); } catch (RuntimeException | Error var3) { throw var3; } catch (Throwable var4) { throw new UndeclaredThrowableException(var4); } } public final String toString() throws { try { return (String)super.h.invoke(this, m2, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } public final Class annotationType() throws { try { return (Class)super.h.invoke(this, m4, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } public final int hashCode() throws { try { return (Integer)super.h.invoke(this, m0, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } public final RetentionPolicy value() throws { try { return (RetentionPolicy)super.h.invoke(this, m3, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } static { try { m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object")); m2 = Class.forName("java.lang.Object").getMethod("toString"); m4 = Class.forName("java.lang.annotation.Retention").getMethod("annotationType"); m0 = Class.forName("java.lang.Object").getMethod("hashCode"); m3 = Class.forName("java.lang.annotation.Retention").getMethod("value"); } catch (NoSuchMethodException var2) { throw new NoSuchMethodError(var2.getMessage()); } catch (ClassNotFoundException var3) { throw new NoClassDefFoundError(var3.getMessage()); } } }
package com.sun.proxy; import chapter04.Table; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.lang.reflect.UndeclaredThrowableException; public final class $Proxy1 extends Proxy implements Table { private static Method m1; private static Method m3; private static Method m2; private static Method m5; private static Method m4; private static Method m0; public $Proxy1(InvocationHandler var1) throws { super(var1); } public final boolean equals(Object var1) throws { try { return (Boolean)super.h.invoke(this, m1, new Object[]{var1}); } catch (RuntimeException | Error var3) { throw var3; } catch (Throwable var4) { throw new UndeclaredThrowableException(var4); } } public final String name() throws { try { return (String)super.h.invoke(this, m3, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } public final String toString() throws { try { return (String)super.h.invoke(this, m2, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } public final Class annotationType() throws { try { return (Class)super.h.invoke(this, m5, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } public final String alias() throws { try { return (String)super.h.invoke(this, m4, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } public final int hashCode() throws { try { return (Integer)super.h.invoke(this, m0, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } static { try { m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object")); m3 = Class.forName("chapter04.Table").getMethod("name"); m2 = Class.forName("java.lang.Object").getMethod("toString"); m5 = Class.forName("chapter04.Table").getMethod("annotationType"); m4 = Class.forName("chapter04.Table").getMethod("alias"); m0 = Class.forName("java.lang.Object").getMethod("hashCode"); } catch (NoSuchMethodException var2) { throw new NoSuchMethodError(var2.getMessage()); } catch (ClassNotFoundException var3) { throw new NoClassDefFoundError(var3.getMessage()); } } }
package com.sun.proxy; import chapter04.Column; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.lang.reflect.UndeclaredThrowableException; public final class $Proxy2 extends Proxy implements Column { private static Method m1; private static Method m7; private static Method m3; private static Method m4; private static Method m2; private static Method m8; private static Method m5; private static Method m6; private static Method m0; public $Proxy2(InvocationHandler var1) throws { super(var1); } public final boolean equals(Object var1) throws { try { return (Boolean)super.h.invoke(this, m1, new Object[]{var1}); } catch (RuntimeException | Error var3) { throw var3; } catch (Throwable var4) { throw new UndeclaredThrowableException(var4); } } public final boolean primary() throws { try { return (Boolean)super.h.invoke(this, m7, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } public final String name() throws { try { return (String)super.h.invoke(this, m3, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } public final String type() throws { try { return (String)super.h.invoke(this, m4, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } public final String toString() throws { try { return (String)super.h.invoke(this, m2, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } public final Class annotationType() throws { try { return (Class)super.h.invoke(this, m8, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } public final int length() throws { try { return (Integer)super.h.invoke(this, m5, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } public final String alias() throws { try { return (String)super.h.invoke(this, m6, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } public final int hashCode() throws { try { return (Integer)super.h.invoke(this, m0, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } static { try { m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object")); m7 = Class.forName("chapter04.Column").getMethod("primary"); m3 = Class.forName("chapter04.Column").getMethod("name"); m4 = Class.forName("chapter04.Column").getMethod("type"); m2 = Class.forName("java.lang.Object").getMethod("toString"); m8 = Class.forName("chapter04.Column").getMethod("annotationType"); m5 = Class.forName("chapter04.Column").getMethod("length"); m6 = Class.forName("chapter04.Column").getMethod("alias"); m0 = Class.forName("java.lang.Object").getMethod("hashCode"); } catch (NoSuchMethodException var2) { throw new NoSuchMethodError(var2.getMessage()); } catch (ClassNotFoundException var3) { throw new NoClassDefFoundError(var3.getMessage()); } } }
如上图,debug运行TestAnno,结合jdk动态生成的代理类可以得出如下结论:
Table、Column是实现了Annotation的特殊接口,而通过反射获取注解返回的是Java运行时生成的动态代理对象$Proxy1(Table的实现类)、$Proxy2(Column实现类)
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
面试官:你对Redis缓存了解吗?面对这11道面试题你是否有很多问号?
前言 关于Redis的知识,总结了一个脑图分享给大家 1、在项目中缓存是如何使用的?为什么要用缓存?缓存使用不当会造成什么后果? 面试官心理分析 这个问题,互联网公司必问,要是一个人连缓存都不太清楚,那确实比较尴尬。 只要问到缓存,上来第一个问题,肯定是先问问你项目哪里用了缓存?为啥要用?不用行不行?如果用了以后可能会有什么不良的后果? 这就是看看你对缓存这个东西背后有没有思考,如果你就是傻乎乎的瞎用,没法给面试官一个合理的解答,那面试官对你印象肯定不太好,觉得你平时思考太少,就知道干活儿。 面试题剖析 项目中缓存是如何使用的? 这个,需要结合自己项目的业务来。 为什么要用缓存? 用缓存,主要有两个用途:高性能、高并发。 高性能 假设这么个场景,你有个操作,一个请求过来,吭哧吭哧你各种乱七八糟操作 mysql,半天查出来一个结果,耗时 600ms。但是这个结果可能接下来几个小时都不会变了,或者变了也可以不用立即反馈给用户。那么此时咋办? 缓存啊,折腾 600ms 查出来的结果,扔缓存里,一个 key 对应一个 value,下次再有人查,别走 mysql折腾 600ms 了,直接从缓存里...
- 下一篇
请规范使用Git
文章收录在 GitHub JavaKeeper ,N线互联网开发必备技能兵器谱 Git 使用规范 团队开发中,遵循一个合理、清晰的 Git 使用流程,是非常重要的。 否则,各种不清晰的分支结构,后续产品迭代或维护都会让人很头疼,再如果每个程序员都提交一堆杂乱无章的commit,后续的快速查找定位问题只能通过阅读代码,也是很低效的。 分支规范 几乎所有的版本控制系统都以某种形式支持分支。 使用分支意味着你可以把你的工作从开发主线上分离开来,以免影响开发主线。有人把 Git 的分支模型称为它的“必杀技特性”,因为基于指针的实现使其足够轻量。 Git 鼓励在工作流程中频繁地使用分支与合并,哪怕一天之内进行许多次,但仍要遵循一定的规范 分支命名 master 分支 master 为主分支,也是用于部署生产环境的分支,master 分支要确保稳定性 master 分支一般由 develop 以及 hotfix 分支合并,任何时间都不能直接修改代码 develop 分支 develop 为开发分支,始终保持最新完成以及bug修复后的代码 一般开发新功能时,feature 分支都是基于 develo...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- CentOS7设置SWAP分区,小内存服务器的救世主
- CentOS7安装Docker,走上虚拟化容器引擎之路
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
- CentOS8安装Docker,最新的服务器搭配容器使用
- SpringBoot2整合Redis,开启缓存,提高访问速度
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- Docker安装Oracle12C,快速搭建Oracle学习环境
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7