动态创建对象,并给对象属性赋值
在开发过程中经常会遇到java对象的属性特征不确定的情况,⽐如属性的名称,属性的类型,属性的取值等不确定的情况,如何在java 运⾏时获取这些信息?动态的设置java对象的属性值?借助java反射机制以及javassist能够轻松解决这些问题。
简单介绍Java的反射原理
Java的反射机制是Java特性之⼀,反射机制是构建框架技术的基础所在。Java程序要能够运⾏,java虚拟机需要事先加载java类,⽬前我们的程序在编译期就已经确定哪些java类需要被加载。
Java的反射机制是在编译时并不确定哪个类需要被加载,⽽是在程序运⾏时才加载、探知、⾃审。这样的特点就是反射。
何为⾃审:通过Java的反射机制能够探知到java类的基本结构,这种对Java类结构探知的能⼒,我们称为Java类的“⾃审”。
Java的反射原理最典型的应⽤就是各种java IDE:⽐如Jcreator,eclipse,idea等,当我们构建出⼀个对象时,去调⽤该对象的⽅法和属性的时候。⼀按点,IDE⼯具就会⾃动的把该对象能够使⽤的所有的⽅法和属性全部都列出来,供我们进⾏选择。这就是利⽤了Java反射的原理,是对我们创建对象的探知、
java定义一维数组并赋值⾃审的过程。
Java的反射API(Reflection API)
Class类:要正确使⽤Java反射机制就得使⽤java.lang.Class这个类。它是Java反射机制的起源。当⼀个类被加载以后,Java虚拟机就会⾃动产⽣⼀个Class对象。通过这个Class对象我们就能获得加载到虚拟机当中这个Class对象对应的⽅法、成员以及构造⽅法的声明和定义等信息。
反射API⽤于反应在当前Java虚拟机中的类、接⼝或者对象信息
功能:(Object object = new Object(),下⾯以对象object进⾏说明)
1. 获取类的Class对象
1. 如果在运⾏时⼀个类的实例已经得到,你可以使⽤ Class c = 对象名.getClass();
例: Class c = Class();Class s = Superclass();
2. 如果你在编译期知道类的名字,你可以使⽤如下的⽅法Class c =java. awt. Button.class; 或者Class c = Integer.TYPE;
3. 如果类名在编译期不知道, 但是在运⾏期可以获得, 你可以使⽤下⾯的⽅法Class c = Class.forName(“类的全路径”);
2. 获取类的Fields ,对Field进⾏赋值
1. Field[] fus = Class().getDeclaredField();
2. Field fu = Class().getDeclaredField(fieldName);//获取对象object的名称为fieldName的属性域。
3. fu.setAccessible(true) ;//设置属性域的访问属性
4. fu.set(object,val); //设置object对象的属性值
3. 获取类的Method
1. Method[] ms= Class().getDeclaredMethods()
4. 获取类的Constructor
5. 新建类的实例
1. 通过Class的函数newInstance
2. 通过Constructor对象的⽅法newInstance.
利⽤Java反射机制我们可以很灵活的对已经加载到Java虚拟机当中的类信息进⾏检测。当然这种检测在对运⾏的性能上会有些减弱,所以什么时候使⽤反射,就要靠业务的需求、⼤⼩,以及经验的积累来决定。
Javassist简要介绍
Javassist是⼀个开源的分析、编辑和创建Java字节码的类库。
关于java字节码的处理,⽬前有很多⼯具,如bcel,asm。不过这些都需要直接跟虚拟机指令打交道。如果你不想了解虚拟机指令,可以采⽤javassist。javassist是jboss的⼀个⼦项⽬,其主要的优点,在于简单,⽽且快速。直接使⽤java编码的形式,⽽不需要了解虚拟机指令,就能动态改变类的结构,或者动态⽣成类。简⽽⾔之:Javassist 能够转换现有类的基本内容,或创建⼀个新类。
Javassist 可以检查、编辑以及创建 Java ⼆进制类。检查⽅⾯基本上与通过 Reflection API 直接在 Java 中进⾏的⼀样。Javassist 使⽤类池 javassist.ClassPool 类跟踪和控制所操作的类。其⼯作⽅式与 JVM 类装载器⾮常相似,但是有⼀个重要的区别是它不是将装载的、要执⾏的类作为应⽤程序的⼀
部分链接,类池使所装载的类可以通过 Javassist API 作为数据使⽤。可以使⽤默认的类池,它是从JVM 搜索路径中装载的,也可以定义⼀个搜索⾃定义路径列表的类池。甚⾄可以直接从字节数组或者流中装载⼆进制类,以及从头开始创建新类。
装载到类池中的类由 javassist.CtClass 实例表⽰。与标准的 Java java.lang.Class 类⼀样, CtClass 提供了检查类数据(如字段和⽅法)的⽅法。不过,这只是 CtClass 的部分内容,它还定义了在类中添加新字段、⽅法和构造函数、以及改变类、⽗类和接⼝的⽅法。奇怪的是,Javassist 没有提供删除⼀个类中字段、⽅法或者构造函数的任何⽅法。
字段、⽅法和构造函数分别由 javassist.CtField、javassist.CtMethod 和 javassist.CtConstructor 的实例表⽰。这些类定义了修改由它们所表⽰的对象的所有⽅法的⽅法,包括⽅法或者构造函数中的实际字节码内容。
⽰例代码
/**
* 动态创建对象,动态添加属性
* 必须先添加属性,再实例化,然后设置属性值
* @author meng
*
*/
public class DynamicCreateObject {
public static Object getDynamicObject(Map<String, String> map) throws Exception{
//创建⼀个名称为Template的类
Object template = addField("Template"+UUID.randomUUID(),map);
return template;
}
public static Object addField(String className,Map<String,String> fieldMap) throws Exception {
// 获取javassist类池
ClassPool pool = Default();
// 创建javassist类
CtClass ctClass = pool.makeClass((Name()));
// 为创建的类ctClass添加属性
Iterator<Entry<String, String>> iterator = Set().iterator();
// 遍历所有的属性
while (iterator.hasNext()) {
Map.Entry<String,String> entry = (Map.Entry<String,String>) ();
String fieldName = (Key();
String fieldValue = (Value();
// 增加属性,这⾥仅仅是增加属性字段
String fieldType = Class().getName();
CtField ctField = new (fieldType),fieldName, ctClass);
ctField.setModifiers(Modifier.PUBLIC);
ctClass.addField(ctField);
}
// 为创建的javassist类转换为java类
Class<?> c = Class();
// 为创建java对象
Object newObject = c.newInstance();
iterator = Set().iterator();
// 遍历所有的属性
/
/ 遍历所有的属性
while (iterator.hasNext()) {
Map.Entry<String,String> entry = (Map.Entry<String,String>) ();
String fieldName = (Key();
String fieldValue = (Value();
// 为属性赋值
setFieldValue(newObject,fieldName,fieldValue);
}
return newObject;
}
public Object getFieldValue(Object object, String fieldName) throws Exception {
Object result = null;
// 获取对象的属性域
Field fu = Class().getDeclaredField(fieldName);
// 设置对象属性域的访问属性
fu.setAccessible(true);
// 获取对象属性域的属性值
result = fu.get(object);
return result;
}
private static Object setFieldValue(Object object, String fieldName, String val) throws Exception { Object result = null;
Field fu = Class().getDeclaredField(fieldName); // 获取对象的属性域// 设置对象属性域的访问属性
fu.setAccessible(true);
// 设置对象属性域的属性值
fu.set(object,val);
// 获取对象属性域的属性值
result = fu.get(object);
return result;
}
}
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论