注意:一般情况下用不到java自定义注解功能,这是因为我们一般是在别人定义好的框架下面运行程序,只要掌握了别人定义好的框架的运行规律和运行规则就已经足够了
@是java注解,即annotation。
1可以理解为插件,是代码级别的插件,在类的方法上写:@XXX,就是在代码上插入了一个插件。
2Java 注解是附加在代码中的一些元信息,用于一些工具在编译、运行时进行解析和使用,起到说明、配置的功能。 注解不会也不能影响代码的实际逻辑,仅仅起到辅助性的作用
3要先学习java的反射机制,然后再来理解java注解
5自定义注解:
java自定义注解
Java 注解是附加在代码中的一些元信息,用于一些工具在编译、运行时进行解析和使用,起到说明、配置的功能。 注解不会也不能影响代码的实际逻辑,仅仅起到辅助性的作用。包含在 java.lang.annotation 包中。
1、元注解
元注解是指注解的注解。包括 @Retention @Target @Document @Inherited四种。
1.1、@Retention: 定义注解的保留策略
@Retention(RetentionPolicy.SOURCE) //注解仅存在于源码中,在class字节码文件中不包含
@Retention(RetentionPolicy.CLASS) // 默认的保留策略,注解会在class字节码文件中存在,但运行时无法获得,
@Retention(RetentionPolicy.RUNTIME) // 注解会在class字节码文件中存在,在运行时可以通过反射获取到
自定义的注解类:
[java] view plain copy
@Retention (RetentionPolicy.RUNTIME) // 注解会在class字节码文件中存在,在运行时可以通过反射获取到 @Target ({ElementType.FIELD,ElementType.METHOD})//定义注解的作用目标**作用范围字段、枚举的常量/方法 @Documented //说明该注解将被包含在javadoc中 public @interface FieldMeta { /** * 是否为序列号 * @return */ boolean id() default false ; /** * 字段名称 * @return */ String name() default "" ; /** * 是否可编辑 * @return */ boolean editable() default true ; /** * 是否在列表中显示 * @return */ boolean summary() default true ; /** * 字段描述 * @return */ String description() default "" ; /** * 排序字段 * @return */ int order() default 0 ; }
6自定义注解有什么用?
这个例子很有代表性,读懂就明白了。
http://blog.csdn.net/tengdazhang770960436/article/details/37886361 本例子旨在使用自定义注解为实体打上标记,为自动生成 sql 提供依据,模拟 hibernate 的注解,至于注解的原理自己搜吧
1.定义 Table 注解
[java] view plain copy
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 "" ; } 2.定义 Column 注解
[java] view plain copy
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 "" ; } 3.定义使用注解的实体
[java] view plain copy
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; } } 4.测试注解
[java] view plain copy
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 ); //通过对象,获取该对象的类的相关信息(类的相关信息包括:①用了什么注解 ②类的名称 ③各成员变量的名称等。本例中是通过对象 testDto、testDto1、testDto2获取类的名为“Table”的注解 ),这里就用到了java的反射机制。 StringBuffer sbSql = new StringBuffer(); String tableName = table.value(); //获取成员变量“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; } } 测试结果:
select * from tb_test where 1=1 and _id=123 and username=34 select * from tb_test where 1=1 and _id=123 and username like '%test1%' select * from tb_test where 1=1 and username in (test1,test2,test3,test4)
==========
该例子解析:
1本例子是编写了一个简单的类似于Hibernate的框架,框架的作用是,通过对象的操作的方式,替代写sql语句。
2本例用到了映射机制,什么是java映射?我理解就是:通过类的对象,获取该对象的类的相关信息。obj.getClass().getAnnotation(Table.class )
3注解起到配置文件的作用:
@Table ("tb_test" ) public class TestDto {
意思是,我想将TestDto类和tb_test表绑定起来。
首先new了一个TestDto对象如testDto1,然后进入我的框架(说白了就是文中的assembleSqlFromObj方法)对testDto1进行处理,通过testDto1获取该对象的类即TestDto.Class,然后获取该类的名为“Table”的注解,获取注解类的成员变量(即value)的值,即“tb_test”。
总结:
1java的反射机制就是,通过类的对象,获取该对象的类的相关信息。类的相关信息包括:①用了什么注解 ②类的名称 ③各成员变量的名称等。
2什么时候用到注解?我们一般用不到自定义注解 ,我们平时别人开发好的框架如Hibernate、Spring、Struts等时,只需要按照框架的规则在代码里定义注解即可,而不会在代码里调用和操作注解。只有在自己动手写类似于Hibernate框架的时候,会用到自定义注解。这也是为什么我们一般用不到java反射 ,因为只有在使用自定义注解的时候,才会用到java反射,而我们平时连自定义注解都用不到 。