- 浏览: 409236 次
- 性别:
- 来自: 秦皇岛
最新评论
-
prayjourney:
了解了,讲的不错
DataInputStream和DataOutputStream类 -
niunianss:
将字节退回的时候,需要添加判断,最后一个字符是英文时,实际数组 ...
PushbackInputStream -
cctt_1:
不要误人子弟,那根本就不是 解释器模式!!!那是Composi ...
Interpreter(解释器)模式 -
java-大神:
[i][i]引用引用引用引用[/img][/img][/img ...
BufferedReader和BufferedWriter -
百合不是茶:
你的程序在文件输入输出流中传入agrs[0]时,会报错越界 ...
DataInputStream和DataOutputStream类
1. 使用反射机制,可以在运行时期动态加载类并生成对象,操作对象上的方法、改变类成员的值,甚至连私有成员的值也可以改变。
2. 生成对象:可以使用Class的newInstance()方法来实例化一个对象,实例化的对象以Object类型返回。例如:
Class c = Class.forName(className); Object obj = c.newInstance();
下面是一个简单的示范,可以动态加载实现了List接口的类。
package ysu.hxy; import java.util.*; public class NewInstanceDemo { public static void main(String[] args) { try { Class c = Class.forName(args[0]); List list = (List)c.newInstance(); for(int i = 0;i < 5;i++) { list.add("element " + i); } for(Object o: list.toArray()) { System.out.println(o); } }catch(ClassNotFoundException e) { System.out.println("找不到指定的类"); } catch(InstantiationException e) { e.printStackTrace(); } catch(IllegalAccessException e) { e.printStackTrace(); } } }
运行结果如下:
D:\hxy>java ysu.hxy.NewInstanceDemo java.util.ArrayList
element 0
element 1
element 2
element 3
element 4
实际上如果想要使用反射来动态加载类,通常是对对象的接口或者类型都一无所知,也就无法像上面范例中那样对newInstance()返回的对象进行接口转换动作。后面会介绍如何以反射来调用方法以操作newInstance()所返回的对象。
如果加载的类中具备无参数的构造函数,则可以无参数的newInstance()来构建一个不指定初始变量的对象。如果在动态加载及生成对象时指定对象的初始化变量,则要先指定参数类型、取得Constructor对象、使用Constructor的newInstance()并指定参数的接受值。
下面以一个例子来说明,先来定义一个Student类。
package ysu.hxy; public class Student1 { private String name; private int score; public Student1() { name = "N/A"; } public Student1(String name,int score) { this.name = name; this.score = score; } public void setName(String name) { this.name = name; } public void setScore(int score) { this.score = score; } public String getName() { return name; } public int getScore() { return score; } public String toString() { return name + ":" + score; } }
可以用Class.forName()来加载student1类,并使用第二个有参数的构造函数来构建student实例。如下所示:
package ysu.hxy; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; public class NewInstanceDemo2 { public static void main(String[] args) { try { Class c = Class.forName(args[0]); //指定参数类型 Class[] params = new Class[2]; //第一个参数是String params[0] = String.class; //第二个参数是int,在指定基本类型时要使用对应的包类并使用.TYPE。例如指定int类型时,使用Integer.TYPE,如果要指定Integer类型的参数,才是使用Integer.class。 params[1] = Integer.TYPE; //取得对应参数列的构造函数 Constructor constructor = c.getConstructor(params); //指定变量内容 Object[] argObjs = new Object[2]; argObjs[0] = "caterpillar"; argObjs[1] = new Integer(90); //给定变量并实例化 Object obj = constructor.newInstance(argObjs); //调用toString()来查看描述 System.out.println(obj); } catch(ClassNotFoundException e) { System.out.println("找不到类"); } catch(SecurityException e) { e.printStackTrace(); } catch(NoSuchMethodException e) { System.out.println("没有指定的方法"); } catch(IllegalArgumentException e) { e.printStackTrace(); } catch(InstantiationException e) { e.printStackTrace(); } catch(IllegalAccessException e) { e.printStackTrace(); } catch(InvocationTargetException e) { e.printStackTrace(); } } }
注意,在指定基本类型时,要使用对应的包类(Wrapper)并使用.TYPE。例如指定int类型时,则使用Integer.TYPE,如果要指定Integer类型的参数,才是使用Integer.class。上面的范例会根据指定的变量调用对应的构造函数,运行结果如下:
D:\hxy>java ysu.hxy.NewInstanceDemo2 ysu.hxy.Student1
caterpillar:90
3. 调用方法:
使用反射可以取回类的方法的对象代表,方法的对象代表是java.lang.reflect.Method的实例,可以使用它的invoke() 方法来动态调用指定的方法。如调用上面Student1类的setName()方法,这里以下面范例作为示范:
package ysu.hxy; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class InvokeMethodDemo { public static void main(String[] args) { try { Class c = Class.forName(args[0]); //使用无参数构造函数建立对象 Object targetObj = c.newInstance(); //设定参数类型 Class[] param1 = {String.class}; //根据参数类型取回方法对象 Method setNameMethod = c.getMethod("setName",param1); //设定变量值 Object[] argObjs1 = {"caterpillar"}; //给定变量调用指定对象上的方法,使用方法代表的invoke()方法 setNameMethod.invoke(targetObj,argObjs1); Class[] param2 = {Integer.TYPE}; Method setScoreMethod = c.getMethod("setScore",param2); Object[] argObjs2 = {new Integer(90)}; setScoreMethod.invoke(targetObj,argObjs2); //显示对象描述 System.out.println(targetObj); } catch(ClassNotFoundException e) { System.out.println("找不到类"); } catch(SecurityException e) { e.printStackTrace(); } catch(NoSuchMethodException e) { System.out.println("没有这个方法"); } catch(IllegalArgumentException e) { e.printStackTrace(); } catch(IllegalAccessException e) { e.printStackTrace(); } catch(InvocationTargetException e) { e.printStackTrace(); } catch(InstantiationException e) { e.printStackTrace(); } } }
运行结果:
D:\hxy>java ysu.hxy.InvokeMethodDemo ysu.hxy.Student1
caterpillar:90
此范例指定加载Student1类并生成实例,接着可以动态调用setName()与setScore()方法。范例中参数类型与变量值的设定与前面的范例是类似的,由于调用setName()和setScore()所给定的变量是caterpillar与90,故运行结果也是一样的。
很少的情况下,会需要突破Java的存取限制来调用受保护的或私有的方法(例如有一个组件,但没法修改它的源代码来改变某个私有方法的权限,又一定要调用某个私有方法),这时可以使用反射机制来达到目的。一个存取私有方法的例子如下:
Method privateMethod =
c.getDeclaredMethod("somePrivateMethod",new Class[0]);
privateMethod.setAccessible(true);
privateMethod.invoke(targetObj,argObjs);
使用反射来动态调用方法的实际例子之一是JavaBean的设定,例如在JSP/Servlet中,可以根据使用者的请求名称与JavaBean的属性名称自动比对,将字符串请求值设定至指定的JavaBean上,并自动根据参数类型作类型转换。下面是一个简单的示例,可以给CommandUtil工具类一个Map对象与类名称,然后取得一个更新了值的实例,其中参数Map对象的键为要调用的setter方法名称(不含set,如setName()方法,只要给定键为name即可),而值为要设定给setter的变量。
package ysu.hxy; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.Map; public class CommandUtil { //给定Map对象及要产生的Bean类名称 //可以取回已经设定完成的对象 public static Object getCommand(Map requestMap,String commandClass) throws Exception { Class c = Class.forName(commandClass); Object o = c.newInstance(); return updateCommand(requestMap,o); } //使用reflection自动找出要更新的属性 public static Object updateCommand(Map requestMap,Object command) throws Exception { Method[] methods = command.getClass().getDeclaredMethods(); for(int i = 1;i < methods.length; i++) { //略过private、protected成员且找出必须是以set开头的方法名称 if(!Modifier.isPrivate(methods[i].getModifiers()) && !Modifier.isProtected(methods[i].getModifiers()) && methods[i].getName().startsWith("set")) { //取得不包括set的名称 String name = methods[i].getName().substring(3).toLowerCase(); //如果setter名称与键值相同 //调用对应的setter并设定值 if(requestMap.containsKey(name)) { String param = (String)requestMap.get(name); Object[] values = findOutParamValues(param,methods[i]); methods[i].invoke(command,values); } } } return command; } //转换为对应类型的值 private static Object[] findOutParamValues(String param,Method method) { Class[] params = method.getParameterTypes(); Object[] objs = new Object[params.length]; for(int i = 0;i < params.length;i++) { if(params[i] == String.class) { objs[i] = param; } else if(params[i] == Short.TYPE) { short number = Short.parseShort(param); objs[i] = new Short(number); } else if(params[i] == Integer.TYPE) { Integer number = Integer.parseInt(param); objs[i] = new Integer(number); } else if(params[i] == Long.TYPE) { Long number = Long.parseLong(param); objs[i] = new Long(number); } else if(params[i] == Float.TYPE) { Float number = Float.parseFloat(param); objs[i] = new Float(number); } else if(params[i] == Double.TYPE) { Double number = Double.parseDouble(param); objs[i] = new Double(number); } else if(params[i] == Boolean.TYPE) { Boolean number = Boolean.parseBoolean(param); objs[i] = new Boolean(number); } } return objs; } };
CommandUtil可以自动根据方法上的参数类型,将Map对象中的值对象转换为属性上的对应类型,目前它可以转换基本类型与String类型的属性。一个使用CommandUtil类的例子如下:
package ysu.hxy; import java.util.*; public class CommandUtilDemo { public static void main(String[] args) throws Exception { Map<String,String> request = new HashMap<String,String>(); request.put("name","caterpillar"); request.put("score","90"); Object obj = CommandUtil.getCommand(request,args[0]); System.out.println(obj); } }
可以使用此范例加载Student1类,使用CommandUtil.getCommand()方法可以返回一个设定好值的Student实例。虽然设定给request的值是字符串类型,但CommandUtil会使用反射机制来自动转换为属性上的对应类型。一个运行的范例如下:
D:\hxy>java ysu.hxy.CommandUtilDemo ysu.hxy.Student1
caterpillar:90
通过规范方法的命名方式,就可以再通过反射机制加上方法名称的比对,以正确调用对应的方法。
发表评论
-
内部类总结
2009-11-27 14:28 1222一、方法及作用域内的内部类:1.在一个方法内定义的类2.在一个 ... -
finalize()方法终结条件验证 示例代码
2009-09-20 09:23 1348package Initialization; clas ... -
Proxy(代理)模式二
2009-05-15 21:16 15532. 重新思考图像代理: 现在需要思考设计模式是否 ... -
Junit简介
2009-04-08 17:46 16491. 单元测试(Unit Test) 一个单元(Un ... -
Ant简介
2009-04-08 13:10 18521. Ant可以自动完成的任务: (1)编译Java源代 ... -
专题制作--文字编辑器(文字编辑与保存)
2009-04-08 10:43 22151. 文字编辑与保存: (1). 打开文件的处理流 ... -
专题制作--文字编辑器(逻辑实现部分)
2009-04-07 22:35 19061. 事件处理: 在Java中事件以具体的对象来表 ... -
专题制作--文字编辑器(接口部分)
2009-04-07 20:28 21481. Swing入门: 若要使用J2SE来开发窗口应用 ... -
信息绑定(国际化处理)
2009-04-07 20:02 15831. 程序中的一些文字信息可以将之定义在一个属性文件中,而不定 ... -
日志(Logging)
2009-04-07 16:14 17271. 日志(Logging) 程序不免会出现错误,当 ... -
Java中的日期和时间
2009-04-07 11:26 19581. 使用Date: 使用System.cu ... -
meta-annotation
2009-04-07 09:23 30811. 所谓meta-annotation就是Annotati ... -
Annotion
2009-04-06 23:05 16821. Annotation对程序运行没有影响,它的目的在于对编 ... -
使用反射生成与操作对象(二)
2009-04-06 17:04 17551. 修改成员值: 尽管直接存取类的域成员是不被鼓励的 ... -
Java中的反射(二)
2009-04-06 10:42 20761. 当在命令行模式下执行java XXX.class 指令后 ... -
Java中的反射(一)
2009-04-06 09:43 13911. Java提供的反射机制允许您在运行时动态加载类、查看类信 ... -
容器类的线程安全及ThreadLocal类
2009-04-05 21:28 30571. 容器类默认没有考虑 ... -
wait()和notify()
2009-04-05 19:06 13711. wait()、notify()、notifyAll() ... -
Java线程之同步化(Synchronized)主题
2009-04-05 16:44 27131. 如果一个对象所持有的数据可以被多线程同时共享存取,必须 ... -
Java线程(三)
2009-04-05 15:37 18911. Java中的每个线程都 ...
相关推荐
在Java反射JavaBean对象自动生成插入、更新、删除、查询sql语句操作中,主要使用了Java反射机制来获取JavaBean对象的信息,然后根据这些信息生成对应的sql语句。例如,通过Java反射机制可以获取JavaBean对象的成员...
综上所述,C#的反射机制为开发者提供了在运行时动态操作代码的能力,尤其在处理不确定类型的对象或者需要实现动态行为时,反射成为了一种不可或缺的工具。然而,需要注意的是,由于其内在的性能成本,应当合理地在...
反射是Java编程语言的一个核心特性,它允许程序在运行时检查、操作类的信息以及创建对象。通过反射,开发者可以实现高度灵活的应用程序,例如框架、插件系统等,其中非常重要的一环就是能够动态地创建对象。本文将...
在C#中,利用泛型和反射可以创建灵活的数据库操作库,自动根据实体类生成对应的SQL语句。例如,我们可以定义一个泛型方法,接受一个类型参数,这个类型对应于数据库表的实体模型: ```csharp public void Save(T ...
这个"C#反射生成SQL实例"可能包含一个具体的代码示例,展示了如何结合以上知识点来动态构建和执行SQL。通过学习这个实例,开发者可以更好地理解和应用C#反射在实际项目中的功能,提升代码的灵活性和可维护性。
例如,我们可以创建一个自定义的处理器,该处理器会在编译期间检查带有特定注解的类,并自动生成相应的DAO(数据访问对象)类,这些DAO类已经包含了基于注解信息生成的SQL方法。 总的来说,结合注解和反射,开发者...
Java 使用反射创建并操作对象的方法 Java 的反射机制允许程序在运行时动态地创建和操作对象,这是 Java 程序设计中非常重要的一种技术。下面我们将详细介绍 Java 使用反射创建并操作对象的方法。 反射机制概述 ...
反射是.NET Framework 提供的一种机制,允许程序在运行时动态地创建类型的实例,将类型绑定到现有对象,或从现有对象中获取类型。然后,可以调用类型的方法或访问其字段和属性。使用反射可以动态地调用类中的方法,...
在编程领域,反射机制是一种强大的特性,允许程序在运行时检查自身的行为,包括类的信息、对象的状态以及函数的调用等。在C++的世界里,Qt框架提供了一种实现反射的手段,即QMetaObject系统。这个系统允许我们动态地...
在IT行业中,尤其是在Java开发领域,Hibernate是一个广泛使用的对象关系映射(ORM)框架,它极大地简化了数据库操作。本文将深入探讨如何模仿Hibernate的功能,动态生成SQL来保存对象,以及与之相关的技术如注解...
现在我们有了一个包含JSON数据的Map,可以开始使用反射来创建对应的Java对象。假设我们有一个User类: ```java public class User { private String name; private int age; // getters and setters } ``` 接...
总结起来,Java反射机制提供了一种强大的工具,让我们可以在运行时动态地操作类和对象,这包括调用方法和访问私有字段。但同时,也需要注意其可能带来的副作用。在上述示例中,我们展示了如何利用反射来实现计算器的...
- **代码生成和编译**:例如,Apache的Velocity和FreeMarker模板引擎使用反射生成运行时代码。 - **元编程**:允许在运行时检查和修改程序的行为。 - **插件系统**:允许加载未知类并执行其方法。 - **序列化和反...
在IT行业中,反射查询SQL框架是一种高级编程技术,它结合了面向对象的编程特性与数据库操作,使得开发者可以通过对象和属性来动态构建SQL语句,从而实现对数据库的增、删、改、查(CRUD)操作。这种技术极大地提高了...
Java反射 JavaBean 对象自动生成插入、更新、删除、查询 SQL 语句操作 Java 反射是 Java 语言中一个强大的功能,它允许开发者在运行时检查和修改类、方法、字段的行为。Java 反射机制可以动态地创建对象、调用方法...
通过反射,我们可以获取类、接口、属性、方法和事件等元数据信息,并在运行时创建和操作对象。在C#中,`System.Reflection`命名空间提供了关于反射所需的所有类和方法。 动态生成控件是指在程序运行时根据需求创建...
反射通常在Java、Python、C#等面向对象的语言中被广泛使用,它能增加代码的灵活性和动态性。 反射的基本操作包括: 1. **类的动态加载**:在运行时根据字符串形式的类名加载对应的类,无需在编译时就确定所有要用到...
Java 反射生成工具_generatorConfig 是一个用于自动化生成Java Bean及Mapper XML文件的实用工具。在Java开发中,反射机制是一种强大的技术,它允许程序在运行时检查和修改类、对象及其属性。generatorConfig则是利用...
在Java编程中,ORM(Object-Relational Mapping)是一种技术,它允许程序员使用面向对象的方式来操作数据库,将数据库中的表映射为Java对象,而无需编写大量的SQL语句。本主题探讨的是如何通过反射和注解来自定义ORM...
要想使用反射,首先需要获得待操作的类所对应的 Class 对象。java.lang.Class 是所有反射 API 的入口点。通过 Class 对象,可以获悉整个类的结构,包括其modifiers、superclass、实现的 interfaces、fields 和 ...