自定义注解 痛定思痛。 2021-12-21 11:51 355阅读 0赞 注解是一种元数据形式,即注解是属于java的一种数据类型,和类、接口、数组、枚举类似。注解用来修饰,类、方法、变量、参数、包。注解不会对所修饰的代码产生直接的影响。 使用自定义注解的三个过程 * **第一步,定义注解——相当于定义标记;** * **第二步,配置注解——把标记打在需要用到的程序代码中;** * **第三步,解析注解——在编译期或运行时检测到标记,并进行特殊操作。** **定义注解** 注解所使用的关键字是`@interface`。在底层实现上,所有定义的注解都会自动继承java.lang.annotation.Annotation接口。 列子: public @interface CherryAnnotation \{ public String name(); int age() default 18; int\[\] array(); \} **常用的元注解** 有时候你会发现有些注解只能写在方法上面(比如@Override);有些却可以写在类的上面(比如@Deprecated)。那么这些定义该如何做呢?接下来就该元注解出场了!**元注解是专门修饰注解的注解**。 **1.1 @Target** @Target注解,是专门用来限定某个自定义注解能够被应用在哪些Java元素上面的。它使用一个枚举类型定义如下: public enum ElementType \{ /\*\* 类,接口(包括注解类型)或枚举的声明 \*/ TYPE, /\*\* 属性的声明 \*/ FIELD, /\*\* 方法的声明 \*/ METHOD, /\*\* 方法形式参数声明 \*/ PARAMETER, /\*\* 构造方法的声明 \*/ CONSTRUCTOR, /\*\* 局部变量声明 \*/ LOCAL\_VARIABLE, /\*\* 注解类型声明 \*/ ANNOTATION\_TYPE, /\*\* 包的声明 \*/ PACKAGE \} ### **列子:** ### //@CherryAnnotation被限定只能使用在类、接口或方法上面 @Target(value = \{ElementType.TYPE,ElementType.METHOD\}) public @interface CherryAnnotation \{ String name(); int age() default 18; int\[\] array(); \} **1.2 @Retention** @Retention注解,翻译为持久力、保持力。即用来修饰自定义注解的生命力。 注解的生命周期有三个阶段:1、Java源文件阶段;2、编译到class文件阶段;3、运行期阶段。同样使用了RetentionPolicy枚举类型定义了三个阶段: public enum RetentionPolicy \{ /\*\* \* Annotations are to be discarded by the compiler. \* (注解将被编译器忽略掉) \*/ SOURCE, /\*\* \* Annotations are to be recorded in the class file by the compiler \* but need not be retained by the VM at run time. This is the default \* behavior. \* (注解将被编译器记录在class文件中,但在运行时不会被虚拟机保留,这是一个默认的行为) \*/ CLASS, /\*\* \* Annotations are to be recorded in the class file by the compiler and \* retained by the VM at run time, so they may be read reflectively. \* (注解将被编译器记录在class文件中,而且在运行时会被虚拟机保留,因此它们能通过反射被读取到) \* @see java.lang.reflect.AnnotatedElement \*/ RUNTIME \} 我们再详解一下: 如果一个注解被定义为RetentionPolicy.SOURCE,则它将被限定在Java源文件中,那么这个注解即不会参与编译也不会在运行期起任何作用,这个注解就和一个注释是一样的效果,只能被阅读Java文件的人看到; 如果一个注解被定义为RetentionPolicy.CLASS,则它将被编译到Class文件中,那么编译器可以在编译时根据注解做一些处理动作,但是运行时JVM(Java虚拟机)会忽略它,我们在运行期也不能读取到; 如果一个注解被定义为RetentionPolicy.RUNTIME,那么这个注解可以在运行期的加载阶段被加载到Class对象中。那么在程序运行阶段,我们可以通过反射得到这个注解,并通过判断是否有这个注解或这个注解中属性的值,从而执行不同的程序代码段。我们实际开发中的自定义注解几乎都是使用的RetentionPolicy.RUNTIME; 在默认的情况下,自定义注解是使用的RetentionPolicy.CLASS。 **1.3 @Documented** @Documented注解,是被用来指定自定义注解是否能随着被定义的java文件生成到JavaDoc文档当中。 **1.4 @Inherited** @Inherited注解,是指定某个自定义注解如果写在了父类的声明部分,那么子类的声明部分也能自动拥有该注解。@Inherited注解只对那些@Target被定义为ElementType.TYPE的自定义注解起作用。 **自定义注解就完成了** **例子:** @Retention(RetentionPolicy.RUNTIME) @Target(value = \{ElementType.METHOD\}) @Documented public @interface CherryAnnotation \{ String name(); int age() default 18; int\[\] score(); \} 接下来是应用 ### **应用1:** ### package pojos; public class Student \{ @CherryAnnotation(name = "cherry-peng",age = 23,score = \{99,66,77\}) public void study(int times)\{ for(int i = 0; i < times; i++)\{ System.out.println("Good Good Study, Day Day Up!"); \} \} \} 通过反射获取注解内容 public class TestAnnotation \{ public static void main(String\[\] args)\{ try \{ //获取Student的Class对象 Class stuClass = Class.forName("pojos.Student"); //说明一下,这里形参不能写成Integer.class,应写为int.class Method stuMethod = stuClass.getMethod("study",int.class); if(stuMethod.isAnnotationPresent(CherryAnnotation.class))\{ System.out.println("Student类上配置了CherryAnnotation注解!"); //获取该元素上指定类型的注解 CherryAnnotation cherryAnnotation = stuMethod.getAnnotation(CherryAnnotation.class); System.out.println("name: " + cherryAnnotation.name() + ", age: " + cherryAnnotation.age() + ", score: " + cherryAnnotation.score()\[0\]); \}else\{ System.out.println("Student类上没有配置CherryAnnotation注解!"); \} \} catch (ClassNotFoundException e) \{ e.printStackTrace(); \} catch (NoSuchMethodException e) \{ e.printStackTrace(); \} \} \} 解释一下: * 1.如果我们要获得的注解是配置在方法上的,那么我们要从Method对象上获取;如果是配置在属性上,就需要从该属性对应的Field对象上去获取,如果是配置在类型上,需要从Class对象上去获取。总之在谁身上,就从谁身上去获取! * 2.isAnnotationPresent(Class<? extends Annotation> annotationClass)方法是专门判断该元素上是否配置有某个指定的注解; * 3.getAnnotation(Class<A> annotationClass)方法是获取该元素上指定的注解。之后再调用该注解的注解类型元素方法就可以获得配置时的值数据; * 4.反射对象上还有一个方法getAnnotations(),该方法可以获得该对象身上配置的所有的注解。它会返回给我们一个注解数组,需要注意的是该数组的类型是Annotation类型,这个Annotation是一个来自于java.lang.annotation包的接口。 **应用2:** **Table 注解** package test; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Inherited @Target(\{ElementType.TYPE\}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Table \{ String value() default ""; \} **Column 注解** package test; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Inherited @Target(\{ElementType.FIELD\}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Column \{ String value() default ""; \} **TestDto 对象** package test; @Table("tb\_test") public class TestDto \{ @Deprecated private String tt; @Column("\_id") private String id; @Column("username") private String name; public TestDto(String id, String name) \{ super(); this.id = id; this.name = name; \} public String getId() \{ return id; \} public void setId(String id) \{ this.id = id; \} public String getName() \{ return name; \} public void setName(String name) \{ this.name = name; \} \} **测试注解** package test; import java.lang.reflect.Field; import java.lang.reflect.Method; public class Test \{ public static void main(String\[\] args) \{ TestDto testDto = new TestDto("123", "34"); TestDto testDto1 = new TestDto("123", "test1"); TestDto testDto2 = new TestDto("", "test1,test2,test3,test4"); String sql = assembleSqlFromObj(testDto); String sql1 = assembleSqlFromObj(testDto1); String sql2 = assembleSqlFromObj(testDto2); System.out.println(sql); System.out.println(sql1); System.out.println(sql2); \} /\*\* \* 通过注解来组装查询条件,生成查询语句 \* \* @param obj \* @return \*/ public static String assembleSqlFromObj(Object obj) \{ Table table = obj.getClass().getAnnotation(Table.class); StringBuffer sbSql = new StringBuffer(); String tableName = table.value(); sbSql.append("select \* from " + tableName + " where 1=1 "); Field\[\] fileds = obj.getClass().getDeclaredFields(); for (Field f : fileds) \{ String fieldName = f.getName(); String methodName = "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1); try \{ Column column = f.getAnnotation(Column.class); if (column != null) \{ Method method = obj.getClass().getMethod(methodName); String value = (String) method.invoke(obj); if (value != null && !value.equals("")) \{ if (!isNum(column.value()) && !isNum(value)) \{ // 判断参数是不是 in 类型参数 1,2,3 if (value.contains(",")) \{ sbSql.append(" and " + column.value() + " in (" + value + ") "); \} else \{ sbSql.append(" and " + column.value() + " like '%" + value + "%' "); \} \} else \{ sbSql.append(" and " + column.value() + "=" + value + " "); \} \} \} \} catch (Exception e) \{ e.printStackTrace(); \} \} return sbSql.toString(); \} /\*\* \* 检查给定的值是不是 id 类型 1.检查字段名称 2.检查字段值 \* \* @param target \* @return \*/ public static boolean isNum(String target) \{ boolean isNum = false; if (target.toLowerCase().contains("id")) \{ isNum = true; \} if (target.matches("\\\\d+")) \{ isNum = true; \} return isNum; \} \}
相关 自定义注解 自定义注解关键词 @interface。具体实现可参考下面代码。 @Target({ ElementType.FIELD}) @Retention(Reten 本是古典 何须时尚/ 2022年12月05日 09:59/ 0 赞/ 229 阅读
相关 自定义注解 自定义注解 一、注解是什么? 二、使用步骤 1.使用关键字@interface @Target @Retention详解 一、注解是什么 ﹏ヽ暗。殇╰゛Y/ 2022年12月01日 11:57/ 0 赞/ 3 阅读
相关 自定义注解 1、简单介绍注解 注解(Annotation),也叫元数据。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明 旧城等待,/ 2022年10月09日 03:11/ 0 赞/ 224 阅读
相关 自定义注解 什么是注解? 从JDK5开始,Java增加对元数据的支持,也就是注解,注解与注释是有一定区别的,可以把注解理解为代码里的特殊标记,这些标记可以在编译,类加 素颜马尾好姑娘i/ 2022年09月02日 04:18/ 0 赞/ 241 阅读
相关 自定义注解 首先定义注解类: import java.lang.annotation.; @Documented @Target(ElementType.METHOD) @Ret 一时失言乱红尘/ 2022年07月20日 15:18/ 0 赞/ 283 阅读
相关 自定义注解 package cn.stu; import java.lang.annotation.Documented; import java.lan 本是古典 何须时尚/ 2022年07月15日 18:50/ 0 赞/ 210 阅读
相关 自定义注解 自定义注解 @Retention(RetentionPolicy.RUNTIME) // 元注解:注解的注解。此注解表示使注解保留到运行时。 @Target( ゝ一世哀愁。/ 2022年05月31日 12:24/ 0 赞/ 327 阅读
相关 自定义注解 import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; 谁践踏了优雅/ 2022年03月30日 03:30/ 0 赞/ 325 阅读
相关 自定义注解 转载:[https://my.oschina.net/itblog/blog/1525665][https_my.oschina.net_itblog_blog_1525665 红太狼/ 2022年03月19日 08:51/ 0 赞/ 306 阅读
相关 自定义注解 注解是一种元数据形式,即注解是属于java的一种数据类型,和类、接口、数组、枚举类似。注解用来修饰,类、方法、变量、参数、包。注解不会对所修饰的代码产生直接的 痛定思痛。/ 2021年12月21日 11:51/ 0 赞/ 356 阅读
还没有评论,来说两句吧...