通过反射操作泛型和注解
-
在实际的操作中,取得类的信息的操作代码,并不会经常开发。
-
一定要熟悉java.lang.reflect包的作用,反射机制。
-
如何取得属性、方法、构造器的名称,修饰符等。
1.1、有了Class对象能做什么
创建类的对象:调用Class对象的newInstance()方法
-
类必须要有一个无参数的构造器。
-
类的构造器的访问权限需要足够。
难道没有无参构造器就不能创建对象了吗?只要在操作的时候明确的调用类中的构造器,并将参数传递进去之后,才可以实例化操作。
步骤如下:
-
通过Class类的getDeclaredConstructors(Class...parameterTypes)取得本类的指定形参类型的构造器
-
向构造器的形参传递一个对象数组进去,里面包含了构造器中所需的各个参数。
-
通过Constructors实例化对象
调用方法
-
通过反射,调用类中的方法,通过getMethod完成。
-
通过invoke
invoke(对象,"方法的值")
setAccessible
-
Method和Field、Constructors对象都有setAccessible()方法。
-
setAccessible作用是启动和禁用访问安全检查的开关。
-
参数值为true则指示反射的对象在使用时应该取消Java语言访问检查。
-
提高反射的效率。如果代码中必须用反射,而该句代码需要频繁的被调用,那么设置为true。
-
使得原本无法访问的私有成员也可以访问
-
-
参数值为false则指示反射的对象应该实施Java语言访问检查
测试代码,测试性能
//分析性能问题 public class Test10 { //普通方式调用 public static void test01(){ User user = new User(); long startTime = System.currentTimeMillis(); for (int i = 0; i < 1000000000; i++) { user.getName(); } long endTime = System.currentTimeMillis(); System.out.println("普通方式执行10亿次:"+(endTime - startTime) + "ms"); } //反射方式调用 public static void test02() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { User user = new User(); Class c1 = user.getClass(); Method getName = c1.getMethod("getName", null); long startTime = System.currentTimeMillis(); for (int i = 0; i < 1000000000; i++) { getName.invoke(user,null); } long endTime = System.currentTimeMillis(); System.out.println("反射方式执行10亿次:"+(endTime - startTime) + "ms"); } //反射方式调用 关闭检测 public static void test03() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { User user = new User(); Class c1 = user.getClass(); Method getName = c1.getMethod("getName", null); getName.setAccessible(true);//关闭权限检测 long startTime = System.currentTimeMillis(); for (int i = 0; i < 1000000000; i++) { getName.invoke(user,null); } long endTime = System.currentTimeMillis(); System.out.println("关闭检测执行10亿次:"+(endTime - startTime) + "ms"); } public static void main(String[] args) throws InvocationTargetException, NoSuchMethodException, IllegalAccessException { test01(); test02(); test03(); } }
结果
普通方式执行10亿次:0ms 反射方式执行10亿次:1132ms 关闭检测执行10亿次:621ms
反射操作泛型
-
Java采用泛型擦除的机制来引入泛型,Java中的泛型仅仅是给编译器Javac使用 的,确保数据的安全性和免去强制类型转换问题 ,但是一旦编译完成,所有和泛型有关的类型全部擦除。
-
为了通过反射操作这些类型,Java新增了ParameterizedType,GenericArrayType,TypeVariable和WildcardType几种类型来代表不能被归一到Class类中的类型但是又和原始类型齐名的类型。
ParameterizedType:表示一种参数化类型,比如Collection<String>
GenericArrayType:表示一种元素类型是参数化类型或者类型变量的数组类型
TypeVariable:是各种类型变量的公共父接口
WildcardType:代表一种通配符类型表达式
测试代码
//通过反射获取泛型 public class Test11 { public void test01(Map<String,User> map, List<User> list){ System.out.println("test01"); } public Map<String,User> test02(){ System.out.println("test02"); return null; } public static void main(String[] args) throws NoSuchMethodException { Method method = Test11.class.getMethod("test01", Map.class, List.class); Type[] genericParameterTypes = method.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 = Test11.class.getMethod("test02", null); Type genericReturnType = method.getGenericReturnType(); if(genericReturnType instanceof ParameterizedType){ Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments(); for (Type actualTypeArgument : actualTypeArguments) { System.out.println(actualTypeArgument); } } } }
获取注解信息
通过反射操作注解
getAnnotations
getAnnotation
ORM
Object relationship Mapping——>对象关系映射
-
类和表结构对应
-
属性和字段对应
-
对象和记录对应
利用注解和反射完成类和表结构读到映射关系。
测试代码
//练习反射操作注解 public class Test12 { public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException { Class c1 = Class.forName("com.kuang.reflection.Student2"); //通过反射获得注解 Annotation[] annotations = c1.getAnnotations(); for (Annotation annotation : annotations) { System.out.println(annotation); } //获得注解的value的值 Table table = (Table)c1.getAnnotation(Table.class); String value = table.value(); System.out.println(value); //获得类指定的注解 java.lang.reflect.Field f = c1.getDeclaredField("id"); Field annotation = f.getAnnotation(Field.class); System.out.println(annotation.columnName()); System.out.println(annotation.type()); System.out.println(annotation.length()); } } @Table("db_student") class Student2{ @Field(columnName = "db_id",type = "int",length = 10) private int id; @Field(columnName = "db_age",type = "int",length = 10) private int age; @Field(columnName = "db_name",type = "varchar",length = 3) private String name; public Student2() { } public Student2(int id, int age, String name) { this.id = id; this.age = age; this.name = name; } public int getId() { return id; } public void setId(int id) { this.id = id; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Student2{" + "id=" + id + ", age=" + age + ", name='" + name + '\'' + '}'; } } //类名的注解 @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @interface Table{ String value(); } //属性的注解 @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @interface Field{ String columnName(); String type(); int length(); }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix