注解与反射
2021/11/12 23:12:55
本文主要是介绍注解与反射,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
注解与反射
注解加反射,框架构建基础
注解(Annotation)
annotation,对程序作出解释,被程序理解
附加在方法,属性上,给他们添加额外的信息,或者进行什么操作
@Override Java内置对象
元注解
@Target 用于描述注解的使用范围
@Target(ElementType.ANNOTATION_TYPE) public @interface Target { ElementType[] value(); }
value属性返回值ElementType 是enum类型,比如上面的ElementType.ANNOTATION_TYPE
查阅JDKAPI:
public enum ElementType { TYPE, //类,接口(包括注释类型)或枚举声明 FIELD,//字段声明(包括枚举常数) METHOD,//方法声明 PARAMETER,//正式参数声明 CONSTRUCTOR,//构造函数声明 LOCAL_VARIABLE,//局部变量声明 ANNOTATION_TYPE,//注解类型声明 PACKAGE,//包装声明 TYPE_PARAMETER,//键入参数声明 TYPE_USE//使用类型 }
Retention:用于解释注解的生命周期(source-源码, class-编译 ,runtime-运行)
@Retention(RetentionPolicy.RUNTIME) public @interface Retention { RetentionPolicy value(); }
public enum RetentionPolicy { SOURCE, CLASS, RUNTIME }
Document 说明该注解将被包含在Javadoc中,即其注释将成为注释元素的公共API的一部分
Inherited 说明子类可以继承父类中的该注解
自定义注解
@interface自动继承了Java.lang.annotation.Annotation接口
声明注解@interface
要有元注解中的Target与Retention
属性就是一个配置参数
属性类型(可以是数组)就是在注解输入的参数类型
只有一个名为value的属性,可以不用在注解引用时写
其他的要写
有多个引用方法时全都要写,除非配置了default
注解元素必须要有值,在定义注解元素时,经常使用空字符串和0作为默认值
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @TableStudent(value = "学生表注释",name = {"姓名","性别"},age = 18) @interface TableStudent{ String value() default ""; String[] name()default {}; int age() default 0; }
反射(Reflection)
程序在运行时,对未知的类进行探索的过程。
获取一个类有哪些属性、方法、构造器。Java因为反射获得了动态语言的特性,即在运行时可改变其结构
1、获取类的Class对象
Class to1=TestObject.class; Class to2=Class.forName("com.hs.TestObject"); TestObject oo=new TestObject(10); Class to3 = oo.getClass();
2、一个实体类只有一个Class对象,如下图两个对象的内存地址相同
3、一个类被加载后,整个类的结构被封装到Class对象中
即一个加载的类在JVM中只有一个Class实例
在类加载器加载类的时候会生成类的Class对象,然后在类初始化时通过
4、Class对象只能由系统建立对象,只能获得这个对象
类什么时候初始化:
类主动引用发送类的初始化:
JVM启动,先初始化主程序入口所在类,即main方法所在类
new一个类的对象时,下次再new类的初始化已完成
调用类的静态成员(除了final修饰的变量)和静态方法
初始化一个类,发现父类未初始化,则会先初始化它的父类,父类在类加载的链接阶段
类的被动引用:
通过数组定义类引用,不会触发次类的初始化
引用常量不会触发类的初始化,因为常量在类加载的链接阶段就存入到调用类的常量池中了
获取类运行时的完整结构
实体类
public class Category implements Serializable { private static final long serialVersionUID = -95736938451252186L; private Integer cateid; public Integer getCateid() { return cateid; } public void setCateid(Integer cateid) { this.cateid = cateid; } public Category() { } public Category(Integer cateid) { this.cateid = cateid; } }
获得指定的方法,因为重载,所以通过方法名与参数识别指定方法,比如使用有参构造器,传入参数String.Class
Class<Category> c1 = Category.class; //通过获得无参构造器实例化 Constructor<Category> constructor = c1.getConstructor(); Category category1 = constructor.newInstance(); //通过class对象得到该对象的一个实例 Category category = c1.newInstance(); //通过有参构造器实例化 Constructor<Category> constructor1 = c1.getConstructor(String.class); Category category2 = constructor1.newInstance();
//只能获得public修饰的属性 Field[] fields = c1.getFields(); //循环所有属性 Field[] declaredFields = c1.getDeclaredFields(); for (Field declaredField : declaredFields) { System.out.println(declaredField); }
//获取本类中的所有方法,包括私有的(private、protected、默认以及public)的方法。 Method[] declaredMethods = c1.getDeclaredMethods(); for (Method declaredMethod : declaredMethods) { System.out.println(declaredMethod); } //获取本类以及父类或者父接口中所有的公共方法 Method[] methods = c1.getMethods(); for (Method method : methods) { System.out.println(method); }
私有的不能直接使用
可以通过access为true授权使用
//得到Class对象 Class<Category> c1 = Category.class; //通过class对象得到该对象的一个实例 Category category = c1.newInstance(); //得到setName方法,方法没有参数写null Method method = c1.getDeclaredMethod("setName",String.class); //通过方法调用invoke给方法赋值,确定是category实例的方法,方法没有参数写null method.invoke(category,"闪闪"); //输出该实例的Name值 System.out.println(category.getName());
//属性同理 Field field = c1.getDeclaredField("name"); //私有需要授权 field.setAccessible(true); field.set(category,"我"); System.out.println(category.getName());
想要获得反射效率,可以关闭权限检查
反射获取泛型
public void test1(Map<String,Integer> map, List<Double> list){ System.out.println("test1"); } public Map<String,Character> test2(){ System.out.println("test2"); return null; }
@Test public void test() throws NoSuchMethodException { Class<GenericTest> genericTestClass = GenericTest.class; Method test1 = genericTestClass.getMethod("test1", Map.class, List.class); Type[] genericParameterTypes = test1.getGenericParameterTypes(); for (Type genericParameterType : genericParameterTypes) { System.out.println("参数类型"+genericParameterType); if (genericParameterType instanceof ParameterizedType){ Type[] actualTypeArguments = ((ParameterizedType) genericParameterType).getActualTypeArguments(); for (Type actualTypeArgument : actualTypeArguments) { System.out.println(actualTypeArgument); } } } Method test2 = genericTestClass.getMethod("test2", null); Type genericReturnType = test2.getGenericReturnType(); if (genericReturnType instanceof ParameterizedType){ Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments(); for (Type actualTypeArgument : actualTypeArguments) { System.out.println(actualTypeArgument); } } }
反射操作注解
框架原理就是通过反射找到注解中的值,然后将值赋值给对应的属性,所以Springboot可以通过注解实现自动配置
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface TableStudent{ String value() default ""; }
@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface FiledStudent{ String value() ; String name(); int column(); }
@TableStudent("Student_tb") public class Student { @FiledStudent(value = "属性",name = "张三",column =1) private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } }
@Test public void test1() throws NoSuchFieldException, IllegalAccessException, InstantiationException { Class<Student> studentClass = Student.class; Annotation[] annotations = studentClass.getAnnotations(); for (Annotation annotation : annotations) { System.out.println(annotation); } TableStudent annotation = studentClass.getAnnotation(TableStudent.class); String value = annotation.value(); System.out.println(value); Field name = studentClass.getDeclaredField("name"); FiledStudent annotation1 = name.getAnnotation(FiledStudent.class); System.out.println(annotation1.column()); System.out.println(annotation1.name()); System.out.println(annotation1.value()); //通过注解获得值,通过反射给创建实例的属性赋值 Student student = studentClass.newInstance(); name.setAccessible(true); name.set(student,annotation1.name()); System.out.println(student.getName()); }
这篇关于注解与反射的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-30java最新版本是什么,有什么特性?-icode9专业技术文章分享
- 2024-11-30[开源]27.8K star!这款 Postman 替代工具太火了!
- 2024-11-30Gzip 压缩入门教程:轻松掌握文件压缩技巧
- 2024-11-29开源工具的魅力:让文档管理更“聪明”
- 2024-11-29Release-it开发入门教程
- 2024-11-29Rollup 插件入门教程:轻松掌握模块打包
- 2024-11-29从零到一,产品经理如何玩转项目管理和团队协作
- 2024-11-29如何通过精益生产管理工具帮助项目团队实现精准进度控制?
- 2024-11-29低代码应用开发课程:新手入门与基础教程
- 2024-11-29入门指南:全栈低代码开发课程