我看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条评论来说两句吧...