从上周开始,就一直在捣鼓java反射。自己在试着封装一些动态调用java方法的构件。但是总是不是那么如意。一方面,对java反射机制不是那么理解。另一方面,只是为了得到一个公共的java反射方法,然后各种网上找资料。这里,感谢各位网友提供的关于java反射的说明以及代码。这里,要感谢博客园的这篇文章,让我解决了数组反射的问题:Java 反射 Array动态创建数组。 下面,先贴一段之前的反射方法:
protected static HashMap DynamicInvokedSimple(
HashMap datas, HashMap dynamicInvoke)
throws Exception {
HashMap ret = new HashMap();
if (dynamicInvoke != null && dynamicInvoke.size() > 0) {
String logicPath = (String) dynamicInvoke
.get(CommonUtils.DYNAMIC_LOGICPATH);
String logicType = (String) dynamicInvoke
.get(CommonUtils.DYNAMIC_LOGICTYPE);
HashMap paramsMap = (HashMap) dynamicInvoke
.get(CommonUtils.DYNAMIC_PARAMJSON);
if (logicPath == null || "".equals(logicPath)) {
throw new Exception("logicPath不能为空!");
}
if (logicType == null || "".equals(logicType)) {
throw new Exception("logicType不能为空!");
}
String classPath = logicPath.substring(0,
logicPath.lastIndexOf("."));
String methodName = logicPath
.substring(logicPath.lastIndexOf(".") + 1);
Object c;
try {
c = Class.forName(classPath).newInstance();
} catch (Exception e) {
throw new Exception("创建" + classPath + "实例失败!");
}
Object[] paramObjs = new Object[2];
paramObjs[0] = datas;
paramObjs[1] = paramsMap;
try {
ret = (HashMap) (c.getClass().getMethod(methodName,
new Class[] { HashMap.class, HashMap.class }).invoke(c,
paramObjs));
return ret;
} catch (Exception e) {
e.printStackTrace();
throw new Exception("执行" + methodName + "失败!");
}
}
ret.put(CommonUtils.RETCODE, CommonUtils.SUCCESS);
return ret;
}
先说说这个方法,这个方法第一个参数表示的是传入的参数信息,第二个参数里包含的是反射的java信息,包括java的方法路径,java方法中部分参数信息。
但是这个方法有点局限性。
需要反射调用的方法必须带有两个Map参数;
需要反射调用的方法必须返回Map。
在这样的基础上,我决定重新完善下,希望能够得到一个可以定义任意个数参数,任意类型参数,任意返回值类型的方法,并通过java反射机制调用。于是,重新整理下,代码如下:
protected Map DynamicInvokedSimple(
List datas, HashMap dynamicInvoke)
throws Exception {
Map ret = new HashMap();
if (dynamicInvoke != null && dynamicInvoke.size() > 0) {
String logicPath = (String) dynamicInvoke
.get(CommonUtils.DYNAMIC_LOGICPATH);
String logicType = (String) dynamicInvoke
.get(CommonUtils.DYNAMIC_LOGICTYPE);
HashMap paramsMap = (HashMap) dynamicInvoke
.get(CommonUtils.DYNAMIC_PARAMJSON);
if (logicPath == null || "".equals(logicPath)) {
throw new Exception("logicPath不能为空!");
}
if (logicType == null || "".equals(logicType)) {
throw new Exception("logicType不能为空!");
}
String classPath = logicPath.substring(0,
logicPath.lastIndexOf("."));
String methodName = logicPath
.substring(logicPath.lastIndexOf(".") + 1);
Object c;
try {
c = Class.forName(classPath).newInstance();
} catch (Exception e) {
throw new Exception("创建" + classPath + "实例失败!");
}
try {
Method[] methods = c.getClass().getDeclaredMethods(); // 获取方法名
Method methodInfo = null; // 定义方法
for (int i = 0; i < methods.length; i++) {
Method method = methods[i];
/**
* 表示一定是有重载方法,那么不仅需要名字匹配,还需要参数个数匹配
*/
if (null != dynamicInvoke.get(paramsCountName)) {
int methodCount = method.getParameterCount();
int paramCount = Integer.parseInt(dynamicInvoke.get(paramsCountName).toString().substring(0,dynamicInvoke.get(paramsCountName).toString().contains(".")?
dynamicInvoke.get(paramsCountName).toString().indexOf("."):dynamicInvoke.get(paramsCountName).toString().length()));
if (paramCount==methodCount && methodName.equals(method.getName())) {
methodInfo = method;
break;
}
}else{
/**
* 表示一般的方法
*/
if(methodName.equals(method.getName())){
methodInfo = method;
break;
}
}
}
if (null == methodInfo) {
ret.put(CommonUtils.RETCODE, CommonUtils.FAILURE);
ret.put(CommonUtils.RETMSG, PARAMSFAILURE+"或"+METHODFAILURE);
return ret;
}
/**
* 获取参数类型
*/
Class[] types = methodInfo.getParameterTypes();
Class[] args = new Class[methodInfo.getParameterCount()];
Object[] paramObjs = new Object[methodInfo.getParameterCount()];
if(null != paramsMap){
paramObjs[paramObjs.length-1] = paramsMap;
}
if(datas.size() > 0){
for (int i = 0; i < datas.size(); i++) {
paramObjs[i] = datas.get(i);
}
}
for (int i = 0; i < paramObjs.length; i++) {
if (null == paramObjs[i]) {
System.out.println(types[i].getName());
System.out.println(types[i].getSimpleName());
if ("Map".equals(types[i].getSimpleName())) {
paramObjs[i] = new HashMap<>();
}else if ("List".equals(types[i].getSimpleName())) {
paramObjs[i] = new ArrayList<>();
}else if ("Set".equals(types[i].getSimpleName())) {
paramObjs[i] = new HashSet<>();
}else{
try {
/**
* 判断是不是数组
*/
if (Class.forName(types[i].getName()).isArray()) {
/**
* 是数组的处理方法
*/
Class theClass = getClass(types[i].getName());
paramObjs[i] = Array.newInstance(theClass, 0);
}else{
/**
* 如果不是数组的处理方法
*/
boolean bool = true;
for (int j = 0; j < getBasicType().size(); j++) {
String key = getBasicType().get(j);
if (types[i].getName().equals(key)) {
bool = false;
break;
}
}
if (bool) {
paramObjs[i] = Class.forName(types[i].getName()).newInstance();
}else{
paramObjs[i] = getBasicType(types[i].getName());
}
}
} catch (InstantiationException e) {
paramObjs[i] = Class.forName(types[i].getName());
} catch (ClassNotFoundException e) {
paramObjs[i] = getBasicType(types[i].getName());
}
}
}
}
for (int i = 0; i < args.length; i++) {
args[i] = types[i];
}
/**
* 判断方法是否有返回值
*/
if ("void".equals(methodInfo.getReturnType().getName())) {
c.getClass().getMethod(methodName,args
).invoke(c,
paramObjs);
ret.put(CommonUtils.RETCODE, CommonUtils.SUCCESS);
ret.put(CommonUtils.RETMSG, SUCCESS);
return ret;
}
ret.put("data",(c.getClass().getMethod(methodName,args
).invoke(c,
paramObjs)));
ret.put(CommonUtils.RETCODE, CommonUtils.SUCCESS);
ret.put(CommonUtils.RETMSG, SUCCESS);
return ret;
} catch (Exception e) {
ret.put(CommonUtils.RETCODE, CommonUtils.SUCCESS);
ret.put(CommonUtils.RETMSG, SUCCESS);
e.printStackTrace();
throw new Exception("执行" + methodName + "失败!");
}
}
//ret.put(CommonUtils.RETCODE, CommonUtils.SUCCESS);
return ret;
}
/**
* 字节型(byte),短整型(short),整型(int),长整型(long),字符型(char),浮点型(float),双精度型(double),布尔型(boolean)
* @return
*/
private List getBasicType(){
List list = new ArrayList();
list.add("int");
list.add("byte");
list.add("short");
list.add("long");
list.add("char");
list.add("float");
list.add("double");
list.add("boolean");
list.add("java.lang.Integer");
list.add("java.lang.Byte");
list.add("java.lang.Short");
list.add("java.lang.Long");
list.add("java.lang.Character");
list.add("java.lang.Float");
list.add("java.lang.Double");
list.add("java.lang.Boolean");
return list;
}
private Object getBasicType(String key){
if ("int".equals(key)) {
return 0;
}else if ("boolean".equals(key)) {
return false;
}else if ("byte".equals(key)) {
return (byte)0;
}else if ("short".equals(key)) {
return (short)0;
}else if ("long".equals(key)) {
return 0;
}else if ("char".equals(key)) {
return (char)0;
}else if ("float".equals(key)) {
return 0;
}else if ("double".equals(key)) {
return 0;
}else if ("java.lang.Integer".equals(key)) {
return new Integer(0);
}else if ("java.lang.Byte".equals(key)) {
return new Byte("0");
}else if ("java.lang.Short".equals(key)) {
return new Short((short) 0);
}else if ("java.lang.Long".equals(key)) {
return new Long(0);
}else if ("java.lang.Character".equals(key)) {
return new Character('0');
}else if ("java.lang.Float".equals(key)) {
return new Float(0);
}else if ("java.lang.Double".equals(key)) {
return new Double(0);
}else if ("java.lang.Boolean".equals(key)) {
return new Boolean(false);
}
return null;
}
private Class getClass(String className) throws ClassNotFoundException{
if(className.contains("int")) return int.class;
if(className.contains("long")) return long.class;
if(className.contains("boolean")) return boolean.class;
if(className.contains("byte")) return byte.class;
if(className.contains("short")) return short.class;
if(className.contains("char")) return char.class;
if(className.contains("float")) return float.class;
if(className.contains("double")) return double.class;
if(className.contains("String")) return String.class;
return Class.forName(className);
}
我把第一个参数变成一个list了。也就是,无论多少个参数的方法,都可以通过这个方法的反射去实现。如果本来有5个参数,但是用户只传了3个参数,其他剩余的参数,我将直接赋为初始值。在自己处理的过程中,比较麻烦的是基础数据类型和接口。比如,Map的接口有很多,如何根据传入的参数是Map类型,我要怎么去找到他的实现类来初始化值呢。一般需要初始化值的,是因为用户在传入参数的过程中,没有传入。 我在处理Map这样的jdk中自带的集合的时候,我这里也是直接就根据接口创建为它的实现类hashMap了 。还有基本数据类型,我以为可以通过反射里的某个方法,来初始化,最后,我还是创建了一个集合来存放这些基础信息,再通过传入的数据类型进行匹配。 另一个比较麻烦的就是数组,在反射中,数组的创建和对象实例化还有些不同。还好,最终通过网上提供的资料,终于搞定了这个问题。 一个类里可能出现方法的重载,这个时候通过方法反射的时候,就不知道具体该调用哪个方法了。所以,我在传参的过程中,多加了一个控制参数个数的方法,因为重载的方法,参数个数是不同的,但方法名是相同的。最后这个问题算是解决了。 当然,写这个方法的过程中,还有很多数据类型没有考虑到,比如枚举,注解什么的。要彻底理解反射的原理,可能还需要一段时间。总之,这个方法,现在一般的java方法可以通过反射机制动态调用了。 如果有写的不对的地方,希望大家帮我纠正一下。感激不尽。