/** * <html> * <body> * <P> Copyright 1994 JsonInternational</p> * <p> All rights reserved.</p> * <p> Created by Jason</p> * </body> * </html> */ package cn.ucaner.core.annotation; /** Annontation是Java5开始引入的新特征,中文名称叫注解。 它提供了一种安全的类似注释的机制,用来将任何的信息或元数据(metadata)与程序元素(类、方法、成员变量等)进行关联。 为程序的元素(类、方法、成员变量)加上更直观更明了的说明,这些说明信息是与程序的业务逻辑无关,并且供指定的工具或框架使用。 Annontation像一种修饰符一样,应用于包、类型、构造方法、方法、成员变量、参数及本地变量的声明语句中。 Java注解是附加在代码中的一些元信息,用于一些工具在编译、运行时进行解析和使用,起到说明、配置的功能。 注解不会也不能影响代码的实际逻辑,仅仅起到辅助性的作用。 包含在 java.lang.annotation 包中。 常见的用法 : 1、生成文档。这是最常见的,也是java 最早提供的注解。常用的有@param @return 等 2、跟踪代码依赖性,实现替代配置文件功能。比如Dagger 2依赖注入,未来java开发,将大量注解配置,具有很大用处; 3、在编译时进行格式检查。如@override 放在方法前,如果你这个方法并不是覆盖了超类方法,则编译时就能检查出。 注解的原理: 注解本质是一个继承了Annotation的特殊接口,其具体实现类是Java运行时生成的动态代理类。 而我们通过反射获取注解时,返回的是Java运行时生成的动态代理对象$Proxy1。 通过代理对象调用自定义注解(接口)的方法,会最终调用AnnotationInvocationHandler的invoke方法。 该方法会从memberValues这个Map中索引出对应的值。 而memberValues的来源是Java常量池。 元注解: @Documented –注解是否将包含在JavaDoc中 @Retention –什么时候使用该注解 @Target –注解用于什么地方 @Inherited – 是否允许子类继承该注解 1.)@Retention– 定义该注解的生命周期 ● RetentionPolicy.SOURCE : 在编译阶段丢弃。 这些注解在编译结束之后就不再有任何意义,所以它们不会写入字节码。 @Override, @SuppressWarnings都属于这类注解。 ● RetentionPolicy.CLASS : 在类加载的时候丢弃。在字节码文件的处理中有用。注解默认使用这种方式 ● RetentionPolicy.RUNTIME : 始终不会丢弃,运行期也保留该注解,因此可以使用反射机制读取该注解的信息。我们自定义的注解通常使用这种方式。 2.)@Target – 表示该注解用于什么地方。默认值为任何元素,表示该注解用于什么地方。可用的ElementType参数包括 ● ElementType.CONSTRUCTOR:用于描述构造器 ● ElementType.FIELD:成员变量、对象、属性(包括enum实例) ● ElementType.LOCAL_VARIABLE:用于描述局部变量 ● ElementType.METHOD:用于描述方法 ● ElementType.PACKAGE:用于描述包 ● ElementType.PARAMETER:用于描述参数 ● ElementType.TYPE:用于描述类、接口(包括注解类型) 或enum声明 3.)@Documented–一个简单的Annotations标记注解,表示是否将注解信息添加在java文档中。 4.)@Inherited – 定义该注释和子类的关系 @Inherited 元注解是一个标记注解,@Inherited阐述了某个被标注的类型是被继承的。 如果一个使用了@Inherited修饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类。 */ public class AnnoDefined { }
/** * <html> * <body> * <P> Copyright 1994 JsonInternational</p> * <p> All rights reserved.</p> * <p> Created on 19941115</p> * <p> Created by Jason</p> * </body> * </html> */ package cn.ucaner.core.annotation; public class AnnoDemo { @FieldMeta(id=true,name="序列号",order=1,description="ID") private int id; @FieldMeta(name="姓名",order=3,description="姓名") private String name; @FieldMeta(name="年龄",order=2) private int age; @FieldMeta(description="描述",order=4) public String desc(){ return "java反射获取annotation的测试"; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
/** * <html> * <body> * <P> Copyright 1994 JsonInternational</p> * <p> All rights reserved.</p> * <p> Created by Jason</p> * </body> * </html> */ package cn.ucaner.core.annotation; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * @Package:cn.ucaner.core.annotation * @ClassName:FieldMeta * @Description: <p> @FieldMeta - 注解描述信息 </p> * @Author: - Jason * @CreatTime:2018年10月18日 下午9:53:45 * @Modify By: * @ModifyTime: 2018年10月18日 * @Modify marker: * @version V1.0 */ @Retention(RetentionPolicy.RUNTIME) // 注解会在class字节码文件中存在,在运行时可以通过反射获取到 @Target({ElementType.FIELD,ElementType.METHOD})//定义注解的作用目标**作用范围字段、枚举的常量/方法 @Documented//说明该注解将被包含在javadoc中 public @interface FieldMeta { /** * 是否为序列号 * @return */ boolean id() default false; /** * 字段名称 * @return */ String name() default "default_name"; /** * 是否可编辑 * @return */ boolean editable() default true; /** * 是否在列表中显示 * @return */ boolean summary() default true; /** * 字段描述 * @return */ String description() default ""; /** * 排序字段 * @return */ int order() default 0; }
/** * <html> * <body> * <P> Copyright 1994 JsonInternational</p> * <p> All rights reserved.</p> * <p> Created on 19941115</p> * <p> Created by Jason</p> * </body> * </html> */ package cn.ucaner.core.annotation; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /*1.CONSTRUCTOR:用于描述构造器 2.FIELD:用于描述域 3.LOCAL_VARIABLE:用于描述局部变量 4.METHOD:用于描述方法 5.PACKAGE:用于描述包 6.PARAMETER:用于描述参数 7.TYPE:用于描述类、接口(包括注解类型) 或enum声明*/ /*(RetentionPoicy) 1.SOURCE:在源文件中有效(即源文件保留) 2.CLASS:在class文件中有效(即class保留) 3.RUNTIME:在运行时有效(即运行时保留)*/ @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface FruitName { String value() default "Apple"; }
/** * <html> * <body> * <P> Copyright 1994 JsonInternational</p> * <p> All rights reserved.</p> * <p> Created by Jason</p> * </body> * </html> */ package cn.ucaner.core.annotation; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; /** * @Package:cn.ucaner.core.annotation * @ClassName:Parent * @Description: <p> Parent<T> </p> * @Author: - Jason * @CreatTime:2018年10月18日 下午9:54:26 * @Modify By: * @ModifyTime: 2018年10月18日 * @Modify marker: * @version V1.0 */ public class Parent<T> { private Class<T> entity; public Parent() { init(); } public List<SortableField> init(){ List<SortableField> list = new ArrayList<SortableField>(); /**getClass().getGenericSuperclass()返回表示此 Class 所表示的实体(类、接口、基本类型或 void) * 的直接超类的 Type(Class<T>泛型中的类型),然后将其转换ParameterizedType。。 * getActualTypeArguments()返回表示此类型实际类型参数的 Type 对象的数组。 * [0]就是这个数组中第一个了。。 * 简而言之就是获得超类的泛型参数的实际类型。。*/ // entity = (Class<T>)((ParameterizedType)this.getClass().getGenericSuperclass()).getActualTypeArguments()[0]; // FieldMeta filed = entity.getAnnotation(FieldMeta.class); this.getClass().getGenericSuperclass(); //genericSuperclass. if(this.entity!=null){ /**返回类中所有字段,包括公共、保护、默认(包)访问和私有字段,但不包括继承的字段 * entity.getFields();只返回对象所表示的类或接口的所有可访问公共字段 * 在class中getDeclared**()方法返回的都是所有访问权限的字段、方法等; * 可看API * */ Field[] fields = entity.getDeclaredFields(); // for(Field f : fields){ //获取字段中包含fieldMeta的注解 FieldMeta meta = f.getAnnotation(FieldMeta.class); if(meta!=null){ SortableField sf = new SortableField(meta, f); list.add(sf); } } //返回对象所表示的类或接口的所有可访问公共方法 Method[] methods = entity.getMethods(); for(Method m:methods){ FieldMeta meta = m.getAnnotation(FieldMeta.class); if(meta!=null){ SortableField sf = new SortableField(meta,m.getName(),m.getReturnType()); list.add(sf); } } //这种方法是新建FieldSortCom类实现Comparator接口,来重写compare方法实现排序 // Collections.sort(list, new FieldSortCom()); Collections.sort(list, new Comparator<SortableField>() { @Override public int compare(SortableField s1,SortableField s2) { return s1.getMeta().order()-s2.getMeta().order(); // return s1.getName().compareTo(s2.getName());//也可以用compare来比较 } }); } return list; } }
/** * <html> * <body> * <P> Copyright 1994 JsonInternational</p> * <p> All rights reserved.</p> * <p> Created on 19941115</p> * <p> Created by Jason</p> * </body> * </html> */ package cn.ucaner.core.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * @Package:cn.ucaner.core.annotation * @ClassName:SayHiAnnotation * @Description: <p> 自定义注解,用来配置方法</p> * @Author: - Jason * @CreatTime:2018年4月10日 下午9:39:10 * @Modify By: * @ModifyTime: 2018年4月10日 * @Modify marker: * @version V1.0 */ @Retention(RetentionPolicy.RUNTIME) // 表示注解在运行时依然存在 @Target(ElementType.METHOD) // 表示注解可以被使用于方法上 public @interface SayHiAnnotation { String paramValue() default "Jason"; // 表示我的注解需要一个参数 名为"paramValue" 默认值为"Jason" }
/** * <html> * <body> * <P> Copyright 1994 JsonInternational</p> * <p> All rights reserved.</p> * <p> Created on 19941115</p> * <p> Created by Jason</p> * </body> * </html> */ package cn.ucaner.core.annotation; /** * @Package:cn.ucaner.core.annotation * @ClassName:SayHiEmlement * @Description: <p> 要使用SayHiAnnotation的元素所在类 </br> 由于我们定义了只有方法才能使用我们的注解,我们就使用多个方法来进行测试</p> * @Author: - DaoDou * @CreatTime:2018年4月10日 下午9:39:49 * @Modify By: * @ModifyTime: 2018年4月10日 * @Modify marker: * @version V1.0 */ public class SayHiEmlement { // 普通的方法 public void SayHiDefault(String name,String age){ System.out.println("Hi, " + name+age); } // 使用注解并传入参数的方法 @SayHiAnnotation(paramValue="Jack") public void SayHiAnnotation(String name,String age){ System.out.println("Hi, " + name+age); } // 使用注解并使用默认参数的方法 @SayHiAnnotation public void SayHiAnnotationDefault(String name,String age){ System.out.println("Hi, " + name + age); } }
/** * <html> * <body> * <P> Copyright 1994 JsonInternational</p> * <p> All rights reserved.</p> * <p> Created by Jason</p> * </body> * </html> */ package cn.ucaner.core.annotation; import java.lang.reflect.Field; /** * @Package:cn.ucaner.core.annotation * @ClassName:SortableField * @Description: <p> SortableField 可排序字段 </p> * @Author: - Jason * @CreatTime:2018年10月18日 下午9:55:25 * @Modify By: * @ModifyTime: 2018年10月18日 * @Modify marker: * @version V1.0 */ public class SortableField { public SortableField(){} public SortableField(FieldMeta meta, Field field) { super(); this.meta = meta; this.field = field; this.name=field.getName(); this.type=field.getType(); } public SortableField(FieldMeta meta, String name, Class<?> type) { super(); this.meta = meta; this.name = name; this.type = type; } private FieldMeta meta; private Field field; private String name; private Class<?> type; public FieldMeta getMeta() { return meta; } public void setMeta(FieldMeta meta) { this.meta = meta; } public Field getField() { return field; } public void setField(Field field) { this.field = field; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Class<?> getType() { return type; } public void setType(Class<?> type) { this.type = type; } }
/** * <html> * <body> * <P> Copyright 1994 JsonInternational</p> * <p> All rights reserved.</p> * <p> Created by Jason</p> * </body> * </html> */ package cn.ucaner.core.annotation; import java.lang.reflect.Field; /** * @Package:cn.ucaner.core.annotation * @ClassName:TestMain * @Description: <p> TestMain </p> * @Author: - Jason * @CreatTime:2018年10月19日 下午3:17:20 * @Modify By: * @ModifyTime: 2018年10月19日 * @Modify marker: * @version V1.0 */ public class TestMain { @FieldMeta(name="Jason")//注解的使用 private Object obj; @FieldMeta(name="Andy",description="Intersting") private String name; @FruitName(value="Apple") @FieldMeta private String profile; public String getProfile() { return profile; } public void setProfile(String profile) { this.profile = profile; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Object getObj() { return obj; } public void setObj(Object obj) { this.obj = obj; } /** * @Description: Just for test 注解反射的方式拿到元信息数据 * @throws Exception void */ public static void main(String[] args) throws Exception{ Field[] fields = TestMain.class.getDeclaredFields(); for (Field field : fields) { System.out.println(field.getName()); if(field.isAnnotationPresent(FieldMeta.class)){ FieldMeta fieldMeta = field.getAnnotation(FieldMeta.class); String str = fieldMeta.name(); String description = fieldMeta.description(); System.out.println(str); System.out.println(description); }if (field.isAnnotationPresent(FruitName.class)) { FruitName fruitName = field.getAnnotation(FruitName.class); System.out.println(fruitName.value()); }else{ //FruitName fruitName = field.getAnnotation(FruitName.class); //System.out.println(fruitName.value()); } } } } //Output //obj //Jason // //name //Andy //Intersting //profile //default_name // //Apple