反射中如何区分参数是基本类型还是所对应的包装类

aimer311 2008-10-10 03:57:11

package demo.test;

import java.lang.reflect.Method;

/**
* Java Reflection Cookbook<br/>
* eg:<br/>
*     Reflection r = new Reflection(A.class);<br/>
*     Reflection r = new Reflection("com.ehi.A");<br/>
*/
@SuppressWarnings("unchecked")
public class Reflection {

private Class clazz;

private Object object;

private Reflection() {

}

/**
* construct method
* @param obj
*/
public Reflection(Object obj) {
this.object = obj;
clazz = obj.getClass();
}

/**
* construct method
* @param className
* @throws Exception
*/
public Reflection(String className) throws Exception {
if (className == null)
clazz = null;
else
clazz = Class.forName(className);
this.object = clazz.newInstance();
}

/**
* 根据方法名,参数,查找对应的方法,并执行
*
* @param methodName
* 方法名
* @param args
* 参数
* @return 方法返回值
* @throws Exception
*/
public Object invoke(String methodName, Object[] args)
throws Exception {
Class[] parameterTypes = getParameterTypes(args);
Method method = clazz.getDeclaredMethod(methodName, parameterTypes);
method.setAccessible(true);
return method.invoke(object, args);
}

private Class[] getParameterTypes(Object[] args) throws Exception {
if(args == null){
return null;
}
Class[] parameterTypes = new Class[args.length];
for (int i = 0, j = args.length; i < j; i++) {
if(args[i] instanceof Integer){
parameterTypes[i] = Integer.TYPE;
}else if(args[i] instanceof Byte){
parameterTypes[i] = Byte.TYPE;
}else if(args[i] instanceof Short){
parameterTypes[i] = Short.TYPE;
}else if(args[i] instanceof Float){
parameterTypes[i] = Float.TYPE;
}else if(args[i] instanceof Double){
parameterTypes[i] = Double.TYPE;
}else if(args[i] instanceof Character){
parameterTypes[i] = Character.TYPE;
}else if(args[i] instanceof Long){
parameterTypes[i] = Long.TYPE;
}else if(args[i] instanceof Boolean){
parameterTypes[i] = Boolean.TYPE;
}else{
parameterTypes[i] = args[i].getClass();
}
}
return parameterTypes;
}

public void print(Integer i){
System.out.println("Integer: "+i.intValue());
}

public void print(int i){
System.out.println("int: "+i);
}

public static boolean isWrapClass(Class clz) {
try {
return ((Class) clz.getField("TYPE").get(null)).isPrimitive();
} catch (Exception e) {
return false;
}
}

public static void main(String[] args) throws Exception {
Reflection r = new Reflection(new Reflection());
Object[] obj = new Object[1];
int i = 333;
obj[0] = i;
//Integer I = new Integer(333);
//obj[0] = I;
r.invoke("print", obj);
}
}

invoke要实现的是根据方法名和输入的参数自动查找对应的方法,并执行之。遇到的问题就是如何区分Object[]里面存储的是一个基本类型还是其对应的包装类?或者这样的思路根本就是有问题的,请提供下其他的思路。

按照以上的程序并不能调用print(Integer i).当然,我知道通过
Method method = clazz.getDeclaredMethod("print", int.class);
Method method = clazz.getDeclaredMethod("print", Integer.class);可以区分这两个函数,这样相当于实现知道参数类型。而如果从所输入的参数来判断是什么类型,再判断调用哪个函数就不清楚了。如:
当obj[0] = 333,表明此时的参数是int型,那么调用的应该是print(int i);
当obj[0] = new Integer(333),表明此时的参数是Integer型,那么调用的应该是print(Integer i);
...全文
331 10 打赏 收藏 转发到动态 举报
写回复
用AI写文章
10 条回复
切换为时间正序
请发表友善的回复…
发表回复
masimos 2008-10-12
  • 打赏
  • 举报
回复
不用区分,反正都是类类型 如int.class
qiandongbo 2008-10-11
  • 打赏
  • 举报
回复
我以前倒真没想过这个问题,学习了~
sunyujia 2008-10-11
  • 打赏
  • 举报
回复
恕我没有看完全部的帖子下结论
你好像不是太喜欢传递Class 参数,只想利用对象取得class是吗,
参考
http://topic.csdn.net/u/20081004/10/5fabcb7a-b3a4-49df-be36-497b90123da6.html

因为帖子帖子太长没看全,看了几个关键字,感觉你的需求是这样的,如果我的帖子对你没用,就当我路过好了,呵呵。
ZangXT 2008-10-11
  • 打赏
  • 举报
回复
原来是说签名的问题。
aimer311 2008-10-11
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 huoyin 的回复:]
你上面说的是一个办法,一般都是先获取方法定义的对象,然后通过该对象去调用方法。如Class.getDeclaredMethod(String name, Class... parameterTypes)返回一个Method对象,然后用Method.invoke(Object obj, Object... args)执行该方法
[/Quote]
你的说法是一个正常的反射执行过程,而我要实现的根本目的是通过参数,自动匹配类型。
基于我的程序,实际上在我要调用invoke方法时,我应该是已经知道我所要调用的方法的具体情况了,包括方法名,方法参数。比如我在调用r.invoke("print", obj, clazz); 前,我已经知道我要调用的肯定是pring(Integer I,int i)这个函数,我原来的反射类中的invoke没有加上Class[] types这个参数是想直接通过传入的参数object[] args去判断类型,(虽然这个类型实际上我们已经是知道的)。改造后的程序对于包装类需要明确指明其参数类型,因为考虑到一边我们自己定义的函数用包装类做为参数比较少。

[Quote=引用 5 楼 sunyujia 的回复:]3.等级低的回帖不一定是不被人看好,等级低的大多数要回帖非常细致花更多时间把事情说明白。我是这么感觉的,不过对于3个三角以上人的帖子,只有你说的就会合理得分 [/Quote]
这是个误会,我账号很久没用了,这个大概是1年两年前的时候写的,现在没有在在意等级,分数这个的。
sunyujia 2008-10-10
  • 打赏
  • 举报
回复
说明3件事情
1.从jdk5后开始有了自动拆装箱,但我不确认自动拆装箱被应用到了反射的级别,你使用jdk1.4就能解开你的一个困惑
2.使用包装类开发比较好,各种情况都不会有问题
3.等级低的回帖不一定是不被人看好,等级低的大多数要回帖非常细致花更多时间把事情说明白。我是这么感觉的,不过对于3个三角以上人的帖子,只有你说的就会合理得分
1-2个三角的帖子经常乱给分我都习惯了。
huoyin 2008-10-10
  • 打赏
  • 举报
回复
你上面说的是一个办法,一般都是先获取方法定义的对象,然后通过该对象去调用方法。如Class.getDeclaredMethod(String name, Class... parameterTypes)返回一个Method对象,然后用Method.invoke(Object obj, Object... args)执行该方法
aimer311 2008-10-10
  • 打赏
  • 举报
回复
当程序执行到如下时:
int i = 333;
obj[0] = i; 内存实际上存储的是一个Integer对象。
也就是说当把i存储到数组后就已经是一个Integer的对象了,那么以后就没办法知道它具体是从对象定义而来还是具体类型而来了。
所以我在想除非在传入的参数中必须包含它具体定义类型的信息。
如:
定义的是int i = 333;那么加上类型信息int.class
定义的是Integer I = 333,那么加上类型信息Integer.class.
这样是比较麻烦一点。
当调用的函数包含有基本类型的包装类时,那么必须传入参数的具体类型,否则不需要。因为传入包装类的情况比较少,当然也可以判断当传入的是基本类型是必须加上类型信息。根据上面的想法修改后的程序如下:

package demo.test;

import java.lang.reflect.Method;

/**
* Java Reflection Cookbook<br/>
* eg:<br/>
*     Reflection r = new Reflection(A.class);<br/>
*     Reflection r = new Reflection("com.ehi.A");<br/>
*/
@SuppressWarnings("unchecked")
public class Reflection {

private Class clazz;

private Object object;

private Reflection() {

}

/**
* construct method
* @param obj
*/
public Reflection(Object obj) {
this.object = obj;
clazz = obj.getClass();
}

/**
* construct method
* @param className
* @throws Exception
*/
public Reflection(String className) throws Exception {
if (className == null)
clazz = null;
else
clazz = Class.forName(className);
this.object = clazz.newInstance();
}

/**
* 执行对象方法
* 当所执行的函数的参数包含基本类型的包装类是,必须为所有参数定义其参数类型
* @param methodName
* 方法名
* @param args
* 参数
* @param types
* 当函数的参数包含基本类型的包装类时,此参数包含所以参数的类型信息
* @return 方法返回值
* @throws Exception
*/
public Object invoke(String methodName, Object[] args, Class[] types)
throws Exception {
Class[] parameterTypes = null;
if(types == null)
parameterTypes = getParameterTypes(args);
else
parameterTypes = types;
Method method = clazz.getDeclaredMethod(methodName, parameterTypes);
method.setAccessible(true);
return method.invoke(object, args);
}

private Class[] getParameterTypes(Object[] args) throws Exception {
if(args == null){
return null;
}
Class[] parameterTypes = new Class[args.length];
for (int i = 0, j = args.length; i < j; i++) {
if(args[i] instanceof Integer){
parameterTypes[i] = Integer.TYPE;
}else if(args[i] instanceof Byte){
parameterTypes[i] = Byte.TYPE;
}else if(args[i] instanceof Short){
parameterTypes[i] = Short.TYPE;
}else if(args[i] instanceof Float){
parameterTypes[i] = Float.TYPE;
}else if(args[i] instanceof Double){
parameterTypes[i] = Double.TYPE;
}else if(args[i] instanceof Character){
parameterTypes[i] = Character.TYPE;
}else if(args[i] instanceof Long){
parameterTypes[i] = Long.TYPE;
}else if(args[i] instanceof Boolean){
parameterTypes[i] = Boolean.TYPE;
}else{
parameterTypes[i] = args[i].getClass();
}
}
return parameterTypes;
}

public void print(Integer i, int j){
System.out.println("Integer: "+i.intValue());
System.out.println("int: "+j);
}

public void print(int i){
System.out.println("int: "+i);
}

public static boolean isWrapClass(Class clz) {
try {
return ((Class) clz.getField("TYPE").get(null)).isPrimitive();
} catch (Exception e) {
return false;
}
}

public static void main(String[] args) throws Exception {
Reflection r = new Reflection(new Reflection());
Object[] obj = new Object[2];
Integer I = new Integer(333);
obj[0] = I;
obj[1] = 444;
Class[] clazz = new Class[2];
clazz[0] = Integer.class;
clazz[1] = int.class;
r.invoke("print", obj, clazz);
}
}

aimer311 2008-10-10
  • 打赏
  • 举报
回复
刚去看了下自动开箱,觉得无法应用的我的程序上,楼上要是有办法的话具体说看看

跟踪下我的程序,执行到obj[0] = i;这一步发时候,内存实际上存储的是一个Integer对象。
也就是说当把i存储到数组后就已经是一个Integer的对象了,那么以后就没办法知道它具体是从对象定义而来还是具体类型而来了。
所以我在想出费在传入的参数数组Object[]中必须包含它具体定义类型的信息。
如:
定义的是int i = 333;那么加上类型信息int.class
定义的是Integer I = 333,那么加上类型信息Integer.class.
这样是比较麻烦一点。
meadking 2008-10-10
  • 打赏
  • 举报
回复
5.0自动开箱吧

62,614

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧