Java 反射Reflection总结二
一、简介
上一篇文章总结了一些如何使用反射机制获取类的字段、方法以及构造方法信息的方法;本节主要总结如何通过反射动态调用类的方法、动态创建对象以及一些示例等。
二、反射使用示例
首先,本节的User类需要做一些修改,主要加入了一些静态属性以及静态方法,后面会用到,具体代码如下:
public class User {private int id;private String name;private int age;/*** 静态属性*/private static String flag;/*** 静态方法** @param name* @return*/public static String sayHello(String name) {return name;}public User() {}public User(int id, String name, int age) {this.id = id;this.name = name;this.age = age;}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;}public static String getFlag() {return flag;}public static void setFlag(String flag) {User.flag = flag;}@Overridepublic String toString() {return "User{" +"id=" + id +", name='" + name + '\'' +", age=" + age +'}';}
}
【a】动态调用构造方法创建对象
- 底层调用的是无参构造方法,所以无参构造方法必须显式声明
- clazz.newInstance() : 通过调用Class对象的newInstance()方法创建对象
- constructor.newInstance(Object ... initargs) : 通过调用constructor的newInstance()方法创建对象
/*** @Description: 动态调用构造方法* @author: weishihuai* @Date: 2018/12/19 16:00*/
public class DynamicInvokeConstructor {public static void main(String[] args) {Class<?> clazz;try {clazz = Class.forName("com.wsh.reflection03.User");/*** 动态调用构造方法创建对象:* 1. 底层调用的是无参构造方法,所以无参构造方法必须显式声明* 2. clazz.newInstance() : 通过调用Class对象的newInstance()方法创建对象* 3. constructor.newInstance(Object ... initargs) : 通过调用constructor的newInstance()方法创建对象*/User user = (User) clazz.newInstance();System.out.println(user);Constructor constructor = clazz.getDeclaredConstructor(int.class, String.class, int.class);User user1 = (User) constructor.newInstance(1, "zhangsan", 20);System.out.println(user1);} catch (ClassNotFoundException | IllegalAccessException | InstantiationException | NoSuchMethodException | InvocationTargetException e) {e.printStackTrace();}}
}
注意: 无参构造方法必须要显式声明,否则会报错:
【b】动态调用普通方法/静态方法
- method.invoke(Object obj, Object... args) : obj-调用的实体对象 args:参数值
如果是调用静态方法,那么使用:
- method.invoke(null, Object... args) : obj-null(因为静态方法不属于某个对象,属于整个类,传入null即可) args:参数值
/*** @Description: 动态调用普通方法/静态方法* @author: weishihuai* @Date: 2018/12/19 16:00*/
public class DynamicInvokeMethod {public static void main(String[] args) {Class<?> clazz;try {//通过反射获取User类Class对象clazz = Class.forName("com.wsh.reflection03.User");/*** 通过反射操作普通方法:* method.invoke(Object obj, Object... args) : obj-调用的实体对象 args:参数值*/User user2 = (User) clazz.newInstance();Method method = clazz.getDeclaredMethod("setName", String.class);Method method1 = clazz.getDeclaredMethod("setAge", int.class);method.invoke(user2, "lisi");method1.invoke(user2, 18);System.out.println(user2);Method method2 = clazz.getDeclaredMethod("getName");method2.invoke(user2);System.out.println(user2.getName());/*** 获取静态方法*/Method staticMethod = clazz.getDeclaredMethod("sayHello", String.class);Object o = staticMethod.invoke(null, "zhangsan");System.out.println("动态调用静态方法,返回值-->" + o);} catch (ClassNotFoundException | IllegalAccessException | InstantiationException | NoSuchMethodException | InvocationTargetException e) {e.printStackTrace();}}
}
【c】动态操作字段信息
- field.set(Object obj, Object value): field: 某个字段 obj:实体对象 value:字段值
- field.get(Object obj): field: 某个字段 obj:实体对象
如果操作的是静态属性,那么使用:
- field.set(null, Object value): field: 某个字段 value:字段值
- field.get(null): field: 某个字段
/*** @Description: 动态操作字段信息* @author: weishihuai* @Date: 2018/12/19 16:00*/
public class DynamicInvokeField {public static void main(String[] args) {Class<?> clazz = null;try {clazz = Class.forName("com.wsh.reflection03.User");/*** 通过反射API操作属性:* field.set(Object obj, Object value): field: 某个字段 obj:实体对象 value:字段值* field.get(Object obj): field: 某个字段 obj:实体对象*/User user3 = (User) clazz.newInstance();Field field = clazz.getDeclaredField("name");// //不做安全检查,直接操作属性field.setAccessible(true);field.set(user3, "wangwu");
// //wangwuSystem.out.println(user3.getName());
// //wangwuSystem.out.println(field.get(user3));/*** 获取静态属性*/Field staticField = clazz.getDeclaredField("flag");staticField.setAccessible(true);staticField.set(null, "flag");System.out.println("静态属性flag的值为-->" + staticField.get(null));} catch (ClassNotFoundException | IllegalAccessException | NoSuchFieldException | InstantiationException e) {e.printStackTrace();}}
}
注意,不能直接访问私有属性或者私有构造方法以及私有方法,必须设置 field.setAccessible(true); 跳过安全检查才能访问私有属性、方法以及构造方法。
如果没有设置跳过安全检查直接访问的话,会直接报错,如下代码:
public class DynamicInvokeField {public static void main(String[] args) {Class<?> clazz = null;try {clazz = Class.forName("com.wsh.reflection03.User");/*** 通过反射API操作属性:* field.set(Object obj, Object value): field: 某个字段 obj:实体对象 value:字段值* field.get(Object obj): field: 某个字段 obj:实体对象*/User user3 = (User) clazz.newInstance();Field field = clazz.getDeclaredField("name");// 不能访问私有属性field.set(user3, "wangwu");System.out.println(user3.getName());} catch (ClassNotFoundException | IllegalAccessException | NoSuchFieldException | InstantiationException e) {e.printStackTrace();}}
}
以上就是关于如何通过反射动态操作构造方法、属性、普通方法以及静态方法,下面我们总结一些使用反射的示例:
【d】使用反射跳过泛型检查
大家都知道,泛型检查只是在编译的时候才存在的,对于编译好的Class字节码不存在泛型检查,所以我们可以利用反射获取的Class对象跳过泛型的检查。
/*** @Description: 反射示例一: 绕过泛型检查* @author: weishihuai* @Date: 2018/12/19 16:06*/
public class ReflectionExample01 {public static void main(String[] args) {List<String> namesList = new ArrayList<>();namesList.add("zhangsan");namesList.add("lisi");// 编译器报错,不满足泛型类型要求
// namesList.add(123);System.out.println("改变之前-->" + namesList);//通过反射获取List的Class对象Class<? extends List> clazz = namesList.getClass();try {Method method = clazz.getDeclaredMethod("add", Object.class);method.invoke(namesList, 123);System.out.println("改变之后-->" + namesList);} catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {e.printStackTrace();}}
}
【e】反射操作注解
我们可以通过反射,获取到类上面的注解以及字段甚至方法上面的注解,拿到这些注解的内容以及属性,可以进一步操作。下面的示例是通过反射获取注解中标注的内容信息。
自定义注解Mytable.java
@Target(ElementType.TYPE)
@Retention(value = RetentionPolicy.RUNTIME)
public @interface MyTable {/*** 数据表名称*/String value();
}
自定义注解MyField.java
@Target(ElementType.FIELD)
@Retention(value = RetentionPolicy.RUNTIME)
public @interface MyField {/*** 列名称*/String columnName();/*** 数据类型*/String type();/*** 长度*/int length();}
Student.java:
@MyTable(value = "tb_student")
public class Student {@MyField(columnName = "sname", type = "varchar2", length = 128)private String name;@MyField(columnName = "age", type = "int", length = 3)private int age;@MyField(columnName = "id", type = "int", length = 128)private int id;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;}
}
测试:
public class Demo {public static void main(String[] args) {try {//通过反射获取Student类对象Class clazz = Class.forName("com.wsh.annotation02.Student");//获取Student类的所有有效注解Annotation[] annotations = clazz.getAnnotations();for (Annotation annotation : annotations) {//@com.wsh.annotation02.MyTable(value=tb_student)System.out.println(annotation);}//获取类指定的注解MyTable myTable = (MyTable) clazz.getAnnotation(MyTable.class);System.out.println(myTable.value()); //tb_student//获取类的属性的注解Field name_field = clazz.getDeclaredField("name");MyField nameField = name_field.getAnnotation(MyField.class);System.out.println(nameField.columnName()); //snameSystem.out.println(nameField.type()); //varchar2System.out.println(nameField.length()); //128//至此,各个字段的属性名称、长度、类型都获取了、就可以动态拼接创建数据表的sql...} catch (ClassNotFoundException | NoSuchFieldException e) {e.printStackTrace();}}
}
如上图,成功获取到注解中标注的内容信息,我们进而可以进行下一步的包装处理等。
三、总结
本文是笔者对反射机制之动态操作构造方法、属性、方法的一些总结以及示例,通过两篇文章的总结,相信可以对反射有一个比较深刻的理解,并且可以掌握反射常用的一些使用方法。仅供大家参考,希望能对大家有所帮助。
Java 反射Reflection总结二相关推荐
- java 反射Reflection;Class类
1.反射机制概述 java能够反射的前提:已经加载过这个类 反射可以通过类名来寻找这个类的所有相关信息.类似于人类的记忆,事先在记忆中有了这个事物的信息,人就可以通过名字来在记忆中寻找事物的具体信息. ...
- java反射获取方法内部_公共技术点之 Java 反射 Reflection
本文为 Android 开源项目源码解析 公共技术点中的 Java 反射 部分 分析者:Mr.Simple,校对者:Trinea,校对状态:未完成 1. 了解 Java 中的反射 1.1 什么是 Ja ...
- 公共技术点之 Java 反射 Reflection
1. 了解 Java 中的反射 1.1 什么是 Java 的反射 Java 反射是可以让我们在运行时获取类的函数.属性.父类.接口等 Class 内部信息的机制.通过反射还可以让我们在运行期实例化对象 ...
- java反射字段6,java反射判断字段类型
java动态获取字段类型,深入理解 Java 虚拟机 Java内存区域与内存溢出异常,java反射判断字段类型,java动态添加字段原理 利用java反射获取泛型类的类型参数具体类对象_计算机软件及应 ...
- java反射机制调用带参数的方法_Java反射机制:跟着代码学反射
1. 前言 在OOP的世界里,万物皆对象.也就是说,我们可以将任何东西抽象成一个对象. 比如人,可以抽象成一个Person类,通过new Person()来实例化一个对象:再比如鸭子,可以抽象成一个D ...
- 反射创建对象_如何应用Java反射技术灵活地创建程序类的对象实例
软件项目实训及课程设计指导--如何应用Java反射技术灵活地创建程序类的对象实例 1.如何应用属性配置文件实现对系统中的配置信息进行读写操作 Java中的属性配置文件主要可以作为软件应用系统及项目的配 ...
- Java反射示例教程
Java反射示例教程 Java Reflection提供检查和修改应用程序的运行时行为的能力.Java中的反射是核心java的一个先进主题.使用java反射我们可以检查一个类,在运行时接口,枚举,获取 ...
- 利用Java反射机制降低代码圈复杂度
利用Java反射机制降低代码圈复杂度 在实际的工作中,我遇到了项目里老代码存在圈复杂度过高的问题,在提交代码的时候通不过CI(代码检查)的Lizard复杂度检查,所以迫切需要解决这个问题,运用Java ...
- Javaweb安全——Java反射
Java反射机制 Java反射(Reflection)是Java非常重要的动态特性,通过使用反射我们不仅可以获取到任何类的成员方法(Methods).成员变量(Fields).构造方法(Constru ...
- Java学习之二-Java反射机制
问题: 在运行时,对一个JAVA类,能否知道属性和方法:能否调用它的任意方法? 答案是可以的,JAVA提供一种反射机制可以实现. 目录 什么是JAVA的反射机制 JDK中提供的Reflection A ...
最新文章
- Matlab2013a安装简单教程以及遇到的问题解决(反复提示激活问题)
- python利器怎么编程-bluepy 一款python封装的BLE利器简单介绍
- APP多版本共存,服务端如何兼容?
- RuntimeError: Error occured during execution of the processing block! See the log for more info
- 通过阿里云容器镜像服务海外服务器构建spark-operator镜像
- 算法,求1亿个数的中位数
- Express + mongoDB + nodejs
- c语言中table函数,Excel的TABLE函数是什么意思?
- ActiveMQ的安全配置(九)
- 「软件项目管理」一文详解软件项目管理概述
- 青苹果影视系统源码v1.3.20 多功能开源影视源码
- django-多对多关系
- PBRNet:Progressive Boundary Refinement Network for Temporal Action Detection (AAAI 2020)
- 【Linux】解决用vi修改文件,保存文件时,提示“readonly option is set”
- windows下的工具链 树莓派_Lab2树莓派交叉编译(windows平台)
- Anaconda3安装及opencv配置
- 利用windrose绘制风玫瑰图并解决错误问题
- matlab无限长一维原子链,优·王淑华固体物理答案第三章.ppt
- matplotlib报错:Glyph 25151 (\N{CJK UNIFIED IDEOGRAPH-623F}) missing from current font. func(*args)
- 网络附加存储(NAS)
热门文章
- linux电脑蓝牙传输文件在哪里,Linux操作系统下操作蓝牙手机的方法 -电脑资料
- 极客大学架构师训练营 系统架构 消息队列 负载均衡 数据库备份 第10课 听课总结
- scrapy 保存html页面,28.用配合scrapy的方式爬取本地保存的html
- php mysqli 字段缺失,mysqli 为什么不提示字段异常
- 钉钉微应用怎么进入_海目星激光张荣:激光焊接在锂电池生产应用中越来越多...
- win10 搭建php服务器搭建,Win10平台下安装并配置php
- Struts2中过滤器和拦截器的区别
- android studio | openGL es 3.0增强现实(AR)开发 (4) 绘制简单的2D图形、显示、旋转
- 高斯整数、高斯素数、费马平方和定理
- latex在行末出现百分号的作用