网友投稿 1028 2022-05-30
作为一种重要特性,Java反射机制在很多地方会用到。在此做一小结,供朋友们参考。
首先从一个问题开始着手。
可恶的问题又来了,NoSuchFieldException,如下图所示:
完全不知道这个question是从哪里来的。以前也遇到过这样的问题,后来解决了,但是没有写文档,再次相遇这样的问题,傻了。
经过上网一番查找,发现遇到这个问题的小盆友还真不少,这个问题是属于java反射机制里的。
这是一个反射对象时候的异常,已经被捕获了的。这个报错代码是混淆了的,是不是这个question对象被混淆成其他名了。。
源代码如下:
public static List findMoreRefResult(String sql, List params,Class cls) throws Exception {//加载数据库驱动new MysqlUtil();//连接数据库MysqlUtil.GetConnection();// 构造一个初始容量为 10 的空列表。List list = new ArrayList();// 表示占位符的第一个位置int index = 1;pstmt = connection.prepareStatement(sql);System.out.println("MysqlUtil:" + params);// 判断所填充的占位符是否有值;判断集合的标准方式if (params != null && !params.isEmpty()) {for (int i = 0; i < params.size(); i++) {// 使用给定对象设置指定参数的值。第二个参数必须是Object类型pstmt.setObject(index++, params.get(i));}}// 返回查询结果resultset = pstmt.executeQuery();// 获取列的相关信息java.sql.ResultSetMetaData metdata = resultset.getMetaData();// 获取列数int col_lenth = metdata.getColumnCount();while (resultset.next()) {// 通过反射机制创建一个实例(生成对象)T resultObject = cls.newInstance();for (int i = 0; i < col_lenth; i++) {String cols_name = metdata.getColumnName(i + 1);Object cols_value = resultset.getObject(cols_name);if (cols_value == null) {cols_value = "";}// 通过字段名获得反射(返回一个 Field 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明字段)Field field = cls.getDeclaredField(cols_name);// 打开javabean的私有访问权限field.setAccessible(true);field.set(resultObject, cols_value);}list.add(resultObject);}//关闭数据库MysqlUtil.releaseConn();return list;}调用以上方法的方法如下:public static void main(String[] args) {//Question question = new Question();////Field property = null;//try {//property = question.getClass().getDeclaredField("description");//} catch (NoSuchFieldException e1) {//e1.printStackTrace();//} catch (SecurityException e1) {//e1.printStackTrace();//}// System.out.println(property);List params = new ArrayList();String sql = "SELECT * FROM question ";try {System.out.println(MysqlUtil.findMoreRefResult(sql, params, Question.class));} catch (Exception e) {e.printStackTrace();}}在调用findMoreRefResult()方法的时候,请注意红色背景部分,先获取数据库表中字段名,然后依据该字段名来反射此 Class 对象所表示的类或接口的指定已声明字段。也就是说数据库中的字段名应该与类中的属性字段名一一对应才对,这是符合“建数据表时应与类一一对应”原则的。下面,我们来深入学习一下Java的反射机制,只有做到深入了解某件事情,当这件事情发生问题时,我们自然就会懂得解决之道。注:下面的内容只了解基本的原理就行,代码可忽略。一、反射的基础---ClassClass是所有java类的一个总称,就好像各式各样的人都可以用Person来称呼,每一个类被加载之后都会在内存中生存一个Class对象,这个对象我们通常称之为字节码,而我们通过调用一个类创造的对象其实都是字节码搞出来的,一个类只会产生一份字节码。那么我们怎么获得一个类的Class呢?有三种方式:1.调用某个类的class属性2.使用Class的forName()静态方法3.调用某个对象的getClass()方法。下面我们通过一个实例来展示下上面两点:ClassDemo1.javapackage com.lyl.exercise;public class ClassDemo1 {public static void main(String[] args) throws ClassNotFoundException{String str="iteye";Class cl1=String.class;Class cl2=str.getClass();Class cl3=Class.forName("java.lang.String");System.out.println("str对象与String是同一份字节码吗?"+(cl1==cl2));System.out.println("通过Class.forName()获得的字节码与String.class一样吗?"+(cl1==cl3));}}通过查看JDK文档,我们可以发现,Class有许多方法,通过这些方法我们可以得到java类的相关信息,Constructor,Method,Field等,具体的大家可以参考JDK文档。二、反射的应用那么什么是反射呢?曾经有人说过,反射就是把java类中的各种成分映射成相应的java类。为什么呢?从上一个讲解中大家是否发现,通过Class我们可以解析出一个java类的各种成分,他们返回的也是一个类,所以这句话还是很有道理的。下面让我们来看看反射的一些应用:1.使用反射生成对象通过反射来生成对象有两种方式:a.使用Class对象的newInstance()方法b.使用Class对象获取指定的Constructor对象,再调用Constructor对象的newInstance()方法来创建Class对应类的实例。实例: ClassDemo3.javapackage com.lyl.exercise;import java.lang.reflect.Constructor;public class ClassDemo3 {public static void main(String[] args) throws Exception{//使用Class对象的newInstance()方法String str=(String)Class.forName("java.lang.String").newInstance();//使用Class对象获取指定的Constructor对象,再调用Constructor对象的newInstance()方法来创建Class对应类的实例。Constructor constructor=String.class.getConstructor(StringBuffer.class);String str2=(String)constructor.newInstance(new StringBuffer("abc"));}}2.成员变量的反射接上实例大家看看:ReflectDemo1.javapackage com.lyl.exercise;import java.lang.reflect.Field;public class ReflectDemo1 {public static void main(String[] args) throws Exception {ReflectHelper rh=new ReflectHelper("iteye", "javaeye");Field fieldb=rh.getClass().getField("b");//fieldb只是类的字段,不是对象的,所以要想获得对象上的值,要使用get()方法System.out.println(fieldb.get(rh));//如果我们使用上面方法来访问a的值呢?抛出java.lang.NoSuchFieldException/*Field fielda=rh.getClass().getField("a");System.out.println(fieldb.get(rh));因为a是私有成员变量*///我们可以通过暴力反射来获取它的值Field fielda=rh.getClass().getDeclaredField("a");//设置为可以访问fielda.setAccessible(true);System.out.println(fielda.get(rh));}}ReflectHelper.javapackage com.lyl.exercise;public class ReflectHelper {private String a;public String b;public ReflectHelper(String a,String b){this.a=a;this.b=b;}}如果将上面的搞懂,那么我们不妨来做一道经典的题目:将一个类中所有String类型的成员变量,其中含有的‘a’替换为‘b’。这个题目很明显通过反射可以轻易的完成,大家不妨来看看。package com.lyl.exercise;import java.lang.reflect.Field;public class ReflectDemo2 {public static void main(String[] args) throws Exception {ReflectHelper rh=new ReflectHelper("abc", "basketball");changeStringValue(rh);System.out.println(rh);}private static void changeStringValue(Object object) throws Exception{Field[] fields=object.getClass().getFields();for(Field field:fields){if(field.getType()==String.class){String oldValue=(String)field.get(object);String newValue=oldValue.replace('a','b');//将object的String类型的变量替换为newValuefield.set(object, newValue);}}}}这样就搞定了,是不是很简单?一、ClassLoader初步类加载器负责加载所有的类,系统为所有被载入内存中的类生成一个java.lang.Class实例。一旦一个类被载入到JVM中,同一个类就不会再次被载入了,这是针对同一个加载器,不同的加载器还是可以加载同一个类的,不同加载器加载同一个类在JVM中是不同的。因为在JVM中用类的全限定类名加类加载器作为其唯一标识。在JVM启动时,会形成有三个类加载器组成的初始类加载器层次结构:-->Bootstrap ClassLoader:根类加载器-->Extension ClassLoader:扩展类加载器-->System ClassLoader:系统类加载器Bootstrap ClassLoader是使用C++写的,我们是无法得到它的源码,它是java的核心Loader,比如我们通过String.class.getClassLoader()是获得不到它的名字的,返回的是空值。如果父类加载器加载了某个类,子类就不会加载了。ClassLoader动态加载:a.并非一次性加载b.需要运行时才加载c.可以观察类的具体加载过程:java -verbose:class 在eclipse中只要配置后面的-verbose:classd.static语句块在加载后执行一次。e.dynamic语句块每次new新的对象都会执行等同于构造方法中的语句。用的比较少。具体看参见:http://gzcj.iteye.com/blog/394644二、使用反射实现JDK动态代理在java中提供了Proxy类和一个InvocationHandler接口,通过他们俩我们就可以创建JDK动态代理,下面让我们通过一个实例来看看如何使用吧:Person接口package com.lyl.reflect;public interface Person {void walk();void sayHello(String name);}MyInvocationHandler.javapackage com.lyl.reflect;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;public class MyInvocationHandler implements InvocationHandler {@Overridepublic Object invoke(Object proxy, Method method, Object[] args)throws Throwable {System.out.println("正在运行的方法:"+method);if(args!=null){System.out.println("执行该方法传入的参数:");for(Object arg:args){System.out.println(arg);}}else {System.out.println("该方法没有传入参数!");}return null;}}ProxyTest.javapackage com.lyl.reflect;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Proxy;public class ProxyTest {public static void main(String[] args) {InvocationHandler handler=new MyInvocationHandler();//返回Person接口的代理类实例Person person=(Person)Proxy.newProxyInstance(Person.class.getClassLoader(), new Class[]{Person.class}, handler);person.walk();person.sayHello("ITEYE");}}通过Proxy类的newProxyInstance()方法我们可以获得一个指定接口的代理类实例,在MyInvocationHandler中会自动执行invoke方法,执行结果如下:正在运行的方法:public abstract void com.lyl.reflect.Person.walk()该方法没有传入参数!正在运行的方法:public abstract void com.lyl.reflect.Person.sayHello(java.lang.String)执行该方法传入的参数:ITEYE首先必须明一点 Field类主要是用来辅助获取和操作类的属性的!1.怎么通过反射获取类的属性先来看JDK提供的方法有如下几种:a)Class.getDeclaredField(String name);返回一个 Field 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明字段。b)Class.getDeclaredFields();返回 Field 对象的一个数组,这些对象反映此 Class 对象所表示的类或接口所声明的所有字段。c)Class.getField(String name);返回一个 Field 对象,它反映此 Class 对象所表示的类或接口的指定公共成员字段。d)Class.getField();返回一个包含某些 Field 对象的数组,这些对象反映此 Class 对象所表示的类或接口的所有可访问公共字段。来一个例子来说明一下 :实体类:import java.util.Date;/*** @ClassName: Student* @Description: 学生实体* @author **** @date 2014-3-18 下午5:17:35* @version V1.0*/public class Student{private Long id;private String name;private Date createdate;private String no;public String nickname;public Long getId(){return id;}public void setId(Long id){this.id = id;}public String getName(){return name;}public void setName(String name){this.name = name;}................}测试类:import java.lang.reflect.Field;import java.util.Date;/*** @ClassName: ReflectFieldTest* @Description: 反射Field测试。* @author **** @date 2014-3-18 下午5:16:17* @version V1.0*/public class ReflectFieldTest{public static void main(String[] args){Student stu=new Student();stu.setId(1L);stu.setName("Josean");stu.setNo("201403185203344");stu.setCreatedate(new Date());try{Field property1=stu.getClass().getDeclaredField("name");//private java.lang.String com.cx.test.Student.nameSystem.out.println(property1);Field property3=stu.getClass().getField("nickname");//public java.lang.String com.cx.test.Student.nicknameSystem.out.println(property3);//错误方法 getField系列方法只能获取公共字段//Field property2=stu.getClass().getField("name");//System.out.println(property2);//会抛java.lang.NoSuchFieldException} catch (SecurityException e){e.printStackTrace();} catch (NoSuchFieldException e){e.printStackTrace();}}}2.进行属性获取、更改得到这个Field之后你就可以获取他的值或者设置他的值了。获取它的值用get类型方法,针对常见类型提供了对应get方法,这里就不一一列举了。值得注意的是获取私有属性的时候必须先设置Accessible为true,然后才能获取。同理设置的时候调用set类型方法,这里也不一一列举了,下面放代码。import java.lang.reflect.Field;import java.util.Date;/*** @ClassName: ReflectFieldTest* @Description: 反射Field测试。* @author JoseanLuo* @date 2014-3-18 下午5:16:17* @version V1.0*/public class ReflectFieldTest{public static void main(String[] args) throws Exception{ Student stu=new Student();stu.setId(1L);stu.setName("Josean");stu.setNo("201403185203344");stu.setCreatedate(new Date());stu.setNickname("copyman");Field property1=stu.getClass().getDeclaredField("name");//System.out.println(property1);//out:private java.lang.String com.cx.test.Student.nameField property3=stu.getClass().getField("nickname");System.out.println(property3.get(stu));//System.out.println(property3);//out:public java.lang.String com.cx.test.Student.nickname//错误方法 getField系列方法只能获取公共字段//Field property2=stu.getClass().getField("name");//System.out.println(property2);//会抛java.lang.NoSuchFieldExceptionField [] prFields4=stu.getClass().getDeclaredFields();for(Field field:prFields4){System.out.println(field);System.out.println(field.equals(property1));//私有变量必须先设置Accessible为truefield.setAccessible(true);//获取用get类方法。System.out.println(field.get(stu));}//设置用set类方法property3.set(stu, "名字被我改了,哈哈");System.out.println(stu.getNickname());}}这个是控制台输出:copymanprivate java.lang.Long com.cx.test.Student.idfalse1private java.lang.String com.cx.test.Student.nametrueJoseanprivate java.util.Date com.cx.test.Student.createdatefalseTue Mar 18 18:19:39 CST 2014private java.lang.String com.cx.test.Student.nofalse201403185203344public java.lang.String com.cx.test.Student.nicknamefalsecopyman名字被我改了,哈哈Java 数据库 版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。 上一篇:Git安装以及相关命令 下一篇:Web前端基础(09) 相关文章 Java的语言特点是什么(java语言的主要特点是什么) 1028 2022-05-30 Java都能做什么(Java可以做什么) 1028 2022-05-30 Java-Collections总结(java中Collections) 1028 2022-05-30 推荐文章 企业生产管理是什么,企业生产管理软件进盘点进销存软件排行榜前十名进销存系统哪个简单好用?进销存系统优点工厂生产管理(工厂生产管理流程及制度)生产管理软件,机械制造业生产管理,制造业生产过程管理软件进销存软件和ERP有什么区别?进销存与erp软件理解进销存如何进行库存管理如何利用excel制作销售订单管理系统?数据库订单管理系统有哪些功能?数据库订单管理系统怎么设计?什么是数据库管理系统? 最近发表 提升软件开发与招投标效率的五个方法与技术方案 提升软件开发效率与招投标质量的五个方法 提升软件开发与招投标效率:AI智写助手如何优化智能文档编写 提升软件开发与招投标效率:AI智写助手如何实现智能文档编写 提升软件开发与招投标文档编写效率的AI智写助手 网店运营的关键从订单管理到用户体验 选择适合你的库存盘点软件指南 电商ERP解决方案助力企业实现业务飞跃 云ERP:企业高效管理与数字化转型的利器 销售报表分析的秘密,掌握数据让业绩飞跃 热评文章 零代码开发是什么?2022低代码平台排行榜智能进销存库存管理系统(智慧进销存)在线文档哪家强?8款在线文档编辑软件推荐WPS2016怎么绘制简单的价格表?定制订单管理系统(为特定需求定制的订单管理系统)什么是在线文档?怎么发在线文档 友情链接 伙伴云进销存管理低代码Excel表格海威行FinClip
Class cls) throws Exception {
//加载数据库驱动
new MysqlUtil();
//连接数据库
MysqlUtil.GetConnection();
// 构造一个初始容量为 10 的空列表。
List list = new ArrayList();
// 表示占位符的第一个位置
int index = 1;
pstmt = connection.prepareStatement(sql);
System.out.println("MysqlUtil:" + params);
// 判断所填充的占位符是否有值;判断集合的标准方式
if (params != null && !params.isEmpty()) {
for (int i = 0; i < params.size(); i++) {
// 使用给定对象设置指定参数的值。第二个参数必须是Object类型
pstmt.setObject(index++, params.get(i));
}
// 返回查询结果
resultset = pstmt.executeQuery();
// 获取列的相关信息
java.sql.ResultSetMetaData metdata = resultset.getMetaData();
// 获取列数
int col_lenth = metdata.getColumnCount();
while (resultset.next()) {
// 通过反射机制创建一个实例(生成对象)
T resultObject = cls.newInstance();
for (int i = 0; i < col_lenth; i++) {
String cols_name = metdata.getColumnName(i + 1);
Object cols_value = resultset.getObject(cols_name);
if (cols_value == null) {
cols_value = "";
// 通过字段名获得反射(返回一个 Field 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明字段)
Field field = cls.getDeclaredField(cols_name);
// 打开javabean的私有访问权限
field.setAccessible(true);
field.set(resultObject, cols_value);
list.add(resultObject);
//关闭数据库
MysqlUtil.releaseConn();
return list;
调用以上方法的方法如下:
public static void main(String[] args) {
//Question question = new Question();
//
//Field property = null;
//try {
//property = question.getClass().getDeclaredField("description");
//} catch (NoSuchFieldException e1) {
//e1.printStackTrace();
//} catch (SecurityException e1) {
//}
// System.out.println(property);
List params = new ArrayList();String sql = "SELECT * FROM question ";try {System.out.println(MysqlUtil.findMoreRefResult(sql, params, Question.class));} catch (Exception e) {e.printStackTrace();}}在调用findMoreRefResult()方法的时候,请注意红色背景部分,先获取数据库表中字段名,然后依据该字段名来反射此 Class 对象所表示的类或接口的指定已声明字段。也就是说数据库中的字段名应该与类中的属性字段名一一对应才对,这是符合“建数据表时应与类一一对应”原则的。下面,我们来深入学习一下Java的反射机制,只有做到深入了解某件事情,当这件事情发生问题时,我们自然就会懂得解决之道。注:下面的内容只了解基本的原理就行,代码可忽略。一、反射的基础---ClassClass是所有java类的一个总称,就好像各式各样的人都可以用Person来称呼,每一个类被加载之后都会在内存中生存一个Class对象,这个对象我们通常称之为字节码,而我们通过调用一个类创造的对象其实都是字节码搞出来的,一个类只会产生一份字节码。那么我们怎么获得一个类的Class呢?有三种方式:1.调用某个类的class属性2.使用Class的forName()静态方法3.调用某个对象的getClass()方法。下面我们通过一个实例来展示下上面两点:ClassDemo1.javapackage com.lyl.exercise;public class ClassDemo1 {public static void main(String[] args) throws ClassNotFoundException{String str="iteye";Class cl1=String.class;Class cl2=str.getClass();Class cl3=Class.forName("java.lang.String");System.out.println("str对象与String是同一份字节码吗?"+(cl1==cl2));System.out.println("通过Class.forName()获得的字节码与String.class一样吗?"+(cl1==cl3));}}通过查看JDK文档,我们可以发现,Class有许多方法,通过这些方法我们可以得到java类的相关信息,Constructor,Method,Field等,具体的大家可以参考JDK文档。二、反射的应用那么什么是反射呢?曾经有人说过,反射就是把java类中的各种成分映射成相应的java类。为什么呢?从上一个讲解中大家是否发现,通过Class我们可以解析出一个java类的各种成分,他们返回的也是一个类,所以这句话还是很有道理的。下面让我们来看看反射的一些应用:1.使用反射生成对象通过反射来生成对象有两种方式:a.使用Class对象的newInstance()方法b.使用Class对象获取指定的Constructor对象,再调用Constructor对象的newInstance()方法来创建Class对应类的实例。实例: ClassDemo3.javapackage com.lyl.exercise;import java.lang.reflect.Constructor;public class ClassDemo3 {public static void main(String[] args) throws Exception{//使用Class对象的newInstance()方法String str=(String)Class.forName("java.lang.String").newInstance();//使用Class对象获取指定的Constructor对象,再调用Constructor对象的newInstance()方法来创建Class对应类的实例。Constructor constructor=String.class.getConstructor(StringBuffer.class);String str2=(String)constructor.newInstance(new StringBuffer("abc"));}}2.成员变量的反射接上实例大家看看:ReflectDemo1.javapackage com.lyl.exercise;import java.lang.reflect.Field;public class ReflectDemo1 {public static void main(String[] args) throws Exception {ReflectHelper rh=new ReflectHelper("iteye", "javaeye");Field fieldb=rh.getClass().getField("b");//fieldb只是类的字段,不是对象的,所以要想获得对象上的值,要使用get()方法System.out.println(fieldb.get(rh));//如果我们使用上面方法来访问a的值呢?抛出java.lang.NoSuchFieldException/*Field fielda=rh.getClass().getField("a");System.out.println(fieldb.get(rh));因为a是私有成员变量*///我们可以通过暴力反射来获取它的值Field fielda=rh.getClass().getDeclaredField("a");//设置为可以访问fielda.setAccessible(true);System.out.println(fielda.get(rh));}}ReflectHelper.javapackage com.lyl.exercise;public class ReflectHelper {private String a;public String b;public ReflectHelper(String a,String b){this.a=a;this.b=b;}}如果将上面的搞懂,那么我们不妨来做一道经典的题目:将一个类中所有String类型的成员变量,其中含有的‘a’替换为‘b’。这个题目很明显通过反射可以轻易的完成,大家不妨来看看。package com.lyl.exercise;import java.lang.reflect.Field;public class ReflectDemo2 {public static void main(String[] args) throws Exception {ReflectHelper rh=new ReflectHelper("abc", "basketball");changeStringValue(rh);System.out.println(rh);}private static void changeStringValue(Object object) throws Exception{Field[] fields=object.getClass().getFields();for(Field field:fields){if(field.getType()==String.class){String oldValue=(String)field.get(object);String newValue=oldValue.replace('a','b');//将object的String类型的变量替换为newValuefield.set(object, newValue);}}}}这样就搞定了,是不是很简单?一、ClassLoader初步类加载器负责加载所有的类,系统为所有被载入内存中的类生成一个java.lang.Class实例。一旦一个类被载入到JVM中,同一个类就不会再次被载入了,这是针对同一个加载器,不同的加载器还是可以加载同一个类的,不同加载器加载同一个类在JVM中是不同的。因为在JVM中用类的全限定类名加类加载器作为其唯一标识。在JVM启动时,会形成有三个类加载器组成的初始类加载器层次结构:-->Bootstrap ClassLoader:根类加载器-->Extension ClassLoader:扩展类加载器-->System ClassLoader:系统类加载器Bootstrap ClassLoader是使用C++写的,我们是无法得到它的源码,它是java的核心Loader,比如我们通过String.class.getClassLoader()是获得不到它的名字的,返回的是空值。如果父类加载器加载了某个类,子类就不会加载了。ClassLoader动态加载:a.并非一次性加载b.需要运行时才加载c.可以观察类的具体加载过程:java -verbose:class 在eclipse中只要配置后面的-verbose:classd.static语句块在加载后执行一次。e.dynamic语句块每次new新的对象都会执行等同于构造方法中的语句。用的比较少。具体看参见:http://gzcj.iteye.com/blog/394644二、使用反射实现JDK动态代理在java中提供了Proxy类和一个InvocationHandler接口,通过他们俩我们就可以创建JDK动态代理,下面让我们通过一个实例来看看如何使用吧:Person接口package com.lyl.reflect;public interface Person {void walk();void sayHello(String name);}MyInvocationHandler.javapackage com.lyl.reflect;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;public class MyInvocationHandler implements InvocationHandler {@Overridepublic Object invoke(Object proxy, Method method, Object[] args)throws Throwable {System.out.println("正在运行的方法:"+method);if(args!=null){System.out.println("执行该方法传入的参数:");for(Object arg:args){System.out.println(arg);}}else {System.out.println("该方法没有传入参数!");}return null;}}ProxyTest.javapackage com.lyl.reflect;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Proxy;public class ProxyTest {public static void main(String[] args) {InvocationHandler handler=new MyInvocationHandler();//返回Person接口的代理类实例Person person=(Person)Proxy.newProxyInstance(Person.class.getClassLoader(), new Class[]{Person.class}, handler);person.walk();person.sayHello("ITEYE");}}通过Proxy类的newProxyInstance()方法我们可以获得一个指定接口的代理类实例,在MyInvocationHandler中会自动执行invoke方法,执行结果如下:正在运行的方法:public abstract void com.lyl.reflect.Person.walk()该方法没有传入参数!正在运行的方法:public abstract void com.lyl.reflect.Person.sayHello(java.lang.String)执行该方法传入的参数:ITEYE首先必须明一点 Field类主要是用来辅助获取和操作类的属性的!1.怎么通过反射获取类的属性先来看JDK提供的方法有如下几种:a)Class.getDeclaredField(String name);返回一个 Field 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明字段。b)Class.getDeclaredFields();返回 Field 对象的一个数组,这些对象反映此 Class 对象所表示的类或接口所声明的所有字段。c)Class.getField(String name);返回一个 Field 对象,它反映此 Class 对象所表示的类或接口的指定公共成员字段。d)Class.getField();返回一个包含某些 Field 对象的数组,这些对象反映此 Class 对象所表示的类或接口的所有可访问公共字段。来一个例子来说明一下 :实体类:import java.util.Date;/*** @ClassName: Student* @Description: 学生实体* @author **** @date 2014-3-18 下午5:17:35* @version V1.0*/public class Student{private Long id;private String name;private Date createdate;private String no;public String nickname;public Long getId(){return id;}public void setId(Long id){this.id = id;}public String getName(){return name;}public void setName(String name){this.name = name;}................}测试类:import java.lang.reflect.Field;import java.util.Date;/*** @ClassName: ReflectFieldTest* @Description: 反射Field测试。* @author **** @date 2014-3-18 下午5:16:17* @version V1.0*/public class ReflectFieldTest{public static void main(String[] args){Student stu=new Student();stu.setId(1L);stu.setName("Josean");stu.setNo("201403185203344");stu.setCreatedate(new Date());try{Field property1=stu.getClass().getDeclaredField("name");//private java.lang.String com.cx.test.Student.nameSystem.out.println(property1);Field property3=stu.getClass().getField("nickname");//public java.lang.String com.cx.test.Student.nicknameSystem.out.println(property3);//错误方法 getField系列方法只能获取公共字段//Field property2=stu.getClass().getField("name");//System.out.println(property2);//会抛java.lang.NoSuchFieldException} catch (SecurityException e){e.printStackTrace();} catch (NoSuchFieldException e){e.printStackTrace();}}}2.进行属性获取、更改得到这个Field之后你就可以获取他的值或者设置他的值了。获取它的值用get类型方法,针对常见类型提供了对应get方法,这里就不一一列举了。值得注意的是获取私有属性的时候必须先设置Accessible为true,然后才能获取。同理设置的时候调用set类型方法,这里也不一一列举了,下面放代码。import java.lang.reflect.Field;import java.util.Date;/*** @ClassName: ReflectFieldTest* @Description: 反射Field测试。* @author JoseanLuo* @date 2014-3-18 下午5:16:17* @version V1.0*/public class ReflectFieldTest{public static void main(String[] args) throws Exception{ Student stu=new Student();stu.setId(1L);stu.setName("Josean");stu.setNo("201403185203344");stu.setCreatedate(new Date());stu.setNickname("copyman");Field property1=stu.getClass().getDeclaredField("name");//System.out.println(property1);//out:private java.lang.String com.cx.test.Student.nameField property3=stu.getClass().getField("nickname");System.out.println(property3.get(stu));//System.out.println(property3);//out:public java.lang.String com.cx.test.Student.nickname//错误方法 getField系列方法只能获取公共字段//Field property2=stu.getClass().getField("name");//System.out.println(property2);//会抛java.lang.NoSuchFieldExceptionField [] prFields4=stu.getClass().getDeclaredFields();for(Field field:prFields4){System.out.println(field);System.out.println(field.equals(property1));//私有变量必须先设置Accessible为truefield.setAccessible(true);//获取用get类方法。System.out.println(field.get(stu));}//设置用set类方法property3.set(stu, "名字被我改了,哈哈");System.out.println(stu.getNickname());}}这个是控制台输出:copymanprivate java.lang.Long com.cx.test.Student.idfalse1private java.lang.String com.cx.test.Student.nametrueJoseanprivate java.util.Date com.cx.test.Student.createdatefalseTue Mar 18 18:19:39 CST 2014private java.lang.String com.cx.test.Student.nofalse201403185203344public java.lang.String com.cx.test.Student.nicknamefalsecopyman名字被我改了,哈哈Java 数据库 版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。 上一篇:Git安装以及相关命令 下一篇:Web前端基础(09) 相关文章 Java的语言特点是什么(java语言的主要特点是什么) 1028 2022-05-30 Java都能做什么(Java可以做什么) 1028 2022-05-30 Java-Collections总结(java中Collections) 1028 2022-05-30 推荐文章 企业生产管理是什么,企业生产管理软件进盘点进销存软件排行榜前十名进销存系统哪个简单好用?进销存系统优点工厂生产管理(工厂生产管理流程及制度)生产管理软件,机械制造业生产管理,制造业生产过程管理软件进销存软件和ERP有什么区别?进销存与erp软件理解进销存如何进行库存管理如何利用excel制作销售订单管理系统?数据库订单管理系统有哪些功能?数据库订单管理系统怎么设计?什么是数据库管理系统? 最近发表 提升软件开发与招投标效率的五个方法与技术方案 提升软件开发效率与招投标质量的五个方法 提升软件开发与招投标效率:AI智写助手如何优化智能文档编写 提升软件开发与招投标效率:AI智写助手如何实现智能文档编写 提升软件开发与招投标文档编写效率的AI智写助手 网店运营的关键从订单管理到用户体验 选择适合你的库存盘点软件指南 电商ERP解决方案助力企业实现业务飞跃 云ERP:企业高效管理与数字化转型的利器 销售报表分析的秘密,掌握数据让业绩飞跃 热评文章 零代码开发是什么?2022低代码平台排行榜智能进销存库存管理系统(智慧进销存)在线文档哪家强?8款在线文档编辑软件推荐WPS2016怎么绘制简单的价格表?定制订单管理系统(为特定需求定制的订单管理系统)什么是在线文档?怎么发在线文档 友情链接 伙伴云进销存管理低代码Excel表格海威行FinClip
String sql = "SELECT * FROM question ";
try {
System.out.println(MysqlUtil.findMoreRefResult(sql, params, Question.class));
} catch (Exception e) {
e.printStackTrace();
在调用findMoreRefResult()方法的时候,请注意红色背景部分,先获取数据库表中字段名,然后依据该字段名来反射此 Class 对象所表示的类或接口的指定已声明字段。也就是说数据库中的字段名应该与类中的属性字段名一一对应才对,这是符合“建数据表时应与类一一对应”原则的。
下面,我们来深入学习一下Java的反射机制,只有做到深入了解某件事情,当这件事情发生问题时,我们自然就会懂得解决之道。
注:下面的内容只了解基本的原理就行,代码可忽略。
一、反射的基础---Class
Class是所有java类的一个总称,就好像各式各样的人都可以用Person来称呼,每一个类被加载之后都会在内存中生存一个Class对象,这个对象我们通常称之为字节码,而我们通过调用一个类创造的对象其实都是字节码搞出来的,一个类只会产生一份字节码。
那么我们怎么获得一个类的Class呢?有三种方式:
1.调用某个类的class属性
2.使用Class的forName()静态方法
3.调用某个对象的getClass()方法。
下面我们通过一个实例来展示下上面两点:
ClassDemo1.java
package com.lyl.exercise;
public class ClassDemo1 {
public static void main(String[] args) throws ClassNotFoundException{
String str="iteye";
Class cl1=String.class;
Class cl2=str.getClass();
Class cl3=Class.forName("java.lang.String");
System.out.println("str对象与String是同一份字节码吗?"+(cl1==cl2));
System.out.println("通过Class.forName()获得的字节码与String.class一样吗?"+(cl1==cl3));
通过查看JDK文档,我们可以发现,Class有许多方法,通过这些方法我们可以得到java类的相关信息,Constructor,Method,Field等,具体的大家可以参考JDK文档。
二、反射的应用
那么什么是反射呢?曾经有人说过,反射就是把java类中的各种成分映射成相应的java类。为什么呢?从上一个讲解中大家是否发现,通过Class我们可以解析出一个java类的各种成分,他们返回的也是一个类,所以这句话还是很有道理的。
下面让我们来看看反射的一些应用:
1.使用反射生成对象
通过反射来生成对象有两种方式:
a.使用Class对象的newInstance()方法
b.使用Class对象获取指定的Constructor对象,再调用Constructor对象的newInstance()方法来创建Class对应类的实例。
实例: ClassDemo3.java
import java.lang.reflect.Constructor;
public class ClassDemo3 {
public static void main(String[] args) throws Exception{
//使用Class对象的newInstance()方法
String str=(String)Class.forName("java.lang.String").newInstance();
//使用Class对象获取指定的Constructor对象,再调用Constructor对象的newInstance()方法来创建Class对应类的实例。
Constructor constructor=String.class.getConstructor(StringBuffer.class);
String str2=(String)constructor.newInstance(new StringBuffer("abc"));
2.成员变量的反射
接上实例大家看看:
ReflectDemo1.java
import java.lang.reflect.Field;
public class ReflectDemo1 {
public static void main(String[] args) throws Exception {
ReflectHelper rh=new ReflectHelper("iteye", "javaeye");
Field fieldb=rh.getClass().getField("b");
//fieldb只是类的字段,不是对象的,所以要想获得对象上的值,要使用get()方法
System.out.println(fieldb.get(rh));
//如果我们使用上面方法来访问a的值呢?抛出java.lang.NoSuchFieldException
/*Field fielda=rh.getClass().getField("a");
因为a是私有成员变量
*/
//我们可以通过暴力反射来获取它的值
Field fielda=rh.getClass().getDeclaredField("a");
//设置为可以访问
fielda.setAccessible(true);
System.out.println(fielda.get(rh));
ReflectHelper.java
public class ReflectHelper {
private String a;
public String b;
public ReflectHelper(String a,String b){
this.a=a;
this.b=b;
如果将上面的搞懂,那么我们不妨来做一道经典的题目:将一个类中所有String类型的成员变量,其中含有的‘a’替换为‘b’。
这个题目很明显通过反射可以轻易的完成,大家不妨来看看。
public class ReflectDemo2 {
ReflectHelper rh=new ReflectHelper("abc", "basketball");
changeStringValue(rh);
System.out.println(rh);
private static void changeStringValue(Object object) throws Exception{
Field[] fields=object.getClass().getFields();
for(Field field:fields){
if(field.getType()==String.class){
String oldValue=(String)field.get(object);
String newValue=oldValue.replace('a','b');
//将object的String类型的变量替换为newValue
field.set(object, newValue);
这样就搞定了,是不是很简单?
一、ClassLoader初步
类加载器负责加载所有的类,系统为所有被载入内存中的类生成一个java.lang.Class实例。一旦一个类被载入到JVM中,同一个类就不会再次被载入了,这是针对同一个加载器,不同的加载器还是可以加载同一个类的,不同加载器加载同一个类在JVM中是不同的。因为在JVM中用类的全限定类名加类加载器作为其唯一标识。
在JVM启动时,会形成有三个类加载器组成的初始类加载器层次结构:
-->Bootstrap ClassLoader:根类加载器
-->Extension ClassLoader:扩展类加载器
-->System ClassLoader:系统类加载器
Bootstrap ClassLoader是使用C++写的,我们是无法得到它的源码,它是java的核心Loader,比如我们通过String.class.getClassLoader()是获得不到它的名字的,返回的是空值。
如果父类加载器加载了某个类,子类就不会加载了。
ClassLoader动态加载:
a.并非一次性加载
b.需要运行时才加载
c.可以观察类的具体加载过程:java -verbose:class 在eclipse中只要配置后面的-verbose:class
d.static语句块在加载后执行一次。
e.dynamic语句块每次new新的对象都会执行
等同于构造方法中的语句。
用的比较少。
具体看参见:http://gzcj.iteye.com/blog/394644
二、使用反射实现JDK动态代理
在java中提供了Proxy类和一个InvocationHandler接口,通过他们俩我们就可以创建JDK动态代理,下面让我们通过一个实例来看看如何使用吧:
Person接口
package com.lyl.reflect;
public interface Person {
void walk();
void sayHello(String name);
MyInvocationHandler.java
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class MyInvocationHandler implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("正在运行的方法:"+method);
if(args!=null){
System.out.println("执行该方法传入的参数:");
for(Object arg:args){
System.out.println(arg);
}else {
System.out.println("该方法没有传入参数!");
return null;
ProxyTest.java
import java.lang.reflect.Proxy;
public class ProxyTest {
InvocationHandler handler=new MyInvocationHandler();
//返回Person接口的代理类实例
Person person=(Person)Proxy.newProxyInstance(Person.class.getClassLoader(), new Class[]{Person.class}, handler);
person.walk();
person.sayHello("ITEYE");
通过Proxy类的newProxyInstance()方法我们可以获得一个指定接口的代理类实例,在MyInvocationHandler中会自动执行invoke方法,执行结果如下:
正在运行的方法:public abstract void com.lyl.reflect.Person.walk()
该方法没有传入参数!
正在运行的方法:public abstract void com.lyl.reflect.Person.sayHello(java.lang.String)
执行该方法传入的参数:
ITEYE
首先必须明一点 Field类主要是用来辅助获取和操作类的属性的!
1.怎么通过反射获取类的属性
先来看JDK提供的方法有如下几种:
a)Class.getDeclaredField(String name);
返回一个 Field 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明字段。
b)Class.getDeclaredFields();
返回 Field 对象的一个数组,这些对象反映此 Class 对象所表示的类或接口所声明的所有字段。
c)Class.getField(String name);
返回一个 Field 对象,它反映此 Class 对象所表示的类或接口的指定公共成员字段。
d)Class.getField();
返回一个包含某些 Field 对象的数组,这些对象反映此 Class 对象所表示的类或接口的所有可访问公共字段。
来一个例子来说明一下 :
实体类:
import java.util.Date;
/**
* @ClassName: Student
* @Description: 学生实体
* @author ***
* @date 2014-3-18 下午5:17:35
* @version V1.0
public class Student
{
private Long id;
private String name;
private Date createdate;
private String no;
public String nickname;
public Long getId()
return id;
public void setId(Long id)
this.id = id;
public String getName()
return name;
public void setName(String name)
this.name = name;
................
测试类:
* @ClassName: ReflectFieldTest
* @Description: 反射Field测试。
* @date 2014-3-18 下午5:16:17
public class ReflectFieldTest
public static void main(String[] args)
Student stu=new Student();
stu.setId(1L);
stu.setName("Josean");
stu.setNo("201403185203344");
stu.setCreatedate(new Date());
try
Field property1=stu.getClass().getDeclaredField("name");
//private java.lang.String com.cx.test.Student.name
System.out.println(property1);
Field property3=stu.getClass().getField("nickname");
//public java.lang.String com.cx.test.Student.nickname
System.out.println(property3);
//错误方法 getField系列方法只能获取公共字段
//Field property2=stu.getClass().getField("name");
//System.out.println(property2);
//会抛java.lang.NoSuchFieldException
} catch (SecurityException e)
} catch (NoSuchFieldException e)
2.进行属性获取、更改
得到这个Field之后你就可以获取他的值或者设置他的值了。
获取它的值用get类型方法,针对常见类型提供了对应get方法,这里就不一一列举了。
值得注意的是获取私有属性的时候必须先设置Accessible为true,然后才能获取。
同理设置的时候调用set类型方法,这里也不一一列举了,下面放代码。
* @author JoseanLuo
public static void main(String[] args) throws Exception
{ Student stu=new Student();
stu.setNickname("copyman");
//System.out.println(property1);
//out:private java.lang.String com.cx.test.Student.name
System.out.println(property3.get(stu));
//System.out.println(property3);
//out:public java.lang.String com.cx.test.Student.nickname
Field [] prFields4=stu.getClass().getDeclaredFields();
for(Field field:prFields4)
System.out.println(field);
System.out.println(field.equals(property1));
//私有变量必须先设置Accessible为true
//获取用get类方法。
System.out.println(field.get(stu));
//设置用set类方法
property3.set(stu, "名字被我改了,哈哈");
System.out.println(stu.getNickname());
这个是控制台输出:
copyman
private java.lang.Long com.cx.test.Student.id
false
1
private java.lang.String com.cx.test.Student.name
true
Josean
private java.util.Date com.cx.test.Student.createdate
Tue Mar 18 18:19:39 CST 2014
private java.lang.String com.cx.test.Student.no
201403185203344
public java.lang.String com.cx.test.Student.nickname
名字被我改了,哈哈
Java 数据库
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。