A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© The_Wizard 中级黑马   /  2013-12-9 10:27  /  1544 人查看  /  3 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 The_Wizard 于 2013-12-10 09:04 编辑

不知道对不对。求大家意见,能给内容补充就更好了。谢谢可变参数像是正则表达式,是一种规则。只要传递的参数符合就可以调用该函数,执行它封装的代码。
参照函数:
Mehod类:public Object invoke(Object obj, Object... args)
invoke方法1.5之前:invoke(Object obj, Object[] args)
可变参数为了能兼容以前的(就是1.5以上的JRE能运行1.5之前的程序),所以可变参数更倾向于数组。
可变参数是引用类型:
给函数传递参数。先查看该参数是否是引用数组,如果是,则编译器(应该是编译时,不是运行时)将引用数组拆分成若干个引用。用反射的方式调用一个类的main方法(就最后两句代码。课程是毕老师的22-23,cn.itcast.day1.ReflectTest):
               //22-23
               //Method:invoke()
               //注意:如果该方法是静态的,则 invoke() 的第一个参数(目标对象)为null。
                Method methodCharAt = String.class.getMethod("charAt", int.class);
                System.out.println(methodCharAt.invoke(str1, 1));
                System.out.println(methodCharAt.invoke(str1, new Object[]{2}));
                //TestArguments.main(new String[]{"111","222","333"});
                //主函数需要传递参数:写好参数点击应用,可以让程序记住参数。后边就算修改了代码,也可以直接运行。
//             String startingClassName = args[0];
               String startingClassName = "cn.itcast.day1.TestArguments";
                Method mainMethod = Class.forName(startingClassName).getMethod("main", String[].class);
//              mainMethod.invoke(null, new Object[]{new String[]{"111","222","333"}});
                mainMethod.invoke(null, (Object)new String[]{"111","222","333"});
可变参数是基本类型:
貌似跟引用类型一样。不过应该还有两个问题:
1,怎样用反射获取一个带有可变参数的方法。例如:cn.itcast.day1.VarableParameter的add方法。
2,将cn.itcast.day1.VarableParameter的add方法,修改成add(int x, int[] args)。用反射...现在Method m对应这个函数,此时要用invode方法调用这个函数能像前面的调用main的方式一样吗?main的参数是String[] args,而这里add的参数是int[] args。他们会有不同吗?



评分

参与人数 1黑马币 +3 收起 理由
FFF + 3 赞一个!

查看全部评分

3 个回复

倒序浏览

回帖奖励 +1

{:soso_e179:}
回复 使用道具 举报
楼主的问题是可变参数一个比较难懂的问题,因为涉及到jdk版本向前兼容的问题,在jdk1.5以前,我们知道是没有可变参数的,之前版本中用的是Objecct数组。
对于基本数据类型的可变参数,既可以以多个参数的形式传递,也可以传入一个对应类型的数组,都是可以的向下面这样:
func(new int[]{1,2,3});
func(1,2,3);
public static void func(int...x){
                System.out.println(Arrays.asList(x));
}

但是引用数据类型就不同了,因为要向前兼容,所以在调用带有可变参数的方法时,如果是引用类型,vm会在运行时做一些小动作。
如果你是以多个常量的形式传入实际参数,那没问题,但是,如果你想以数组的形式向其中传递一个参数集,那问题就来了,数组必须是Object类型的数组,如果不是,数组当中的内容会被拆解,每一个元素都会被当作一个Object[]类型,这样就会出现参数个数的错误,所以想要以数组的形式向可变参数的方法中传值的时候要进行Object保护,即把你的数组强制转换成Object类型,这样vm就被你骗过了,他会说:哦,已经是Object[]类型了,那把里面的元素都拿出来吧。
请看下面的例子:
public static void func(String...x){
                System.out.println(Arrays.asList(x));
}
如果这样调用:
Method mth = Test1.class.getMethod("func", String[].class);
mth.invoke(null, new String[]{"a","b"});
那么,你会得到这个
Exception in thread "main" java.lang.IllegalArgumentException: wrong number of arguments
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:601)
        at test.Test1.main(Test1.java:24)
所以,必须对String数组进行包装
Method mth = Test1.class.getMethod("func", String[].class);
mth.invoke(null, (Object)new String[]{"a","b"});

mth.invoke(null, new Object[]{new String[]{"a","b"}});
这样就会得到正确的值。

综上所述:
如果以常量向带有可变参数的方法中传值,那不管是基本数据类型还是引用数据类型都Ok。
如果是引用数据类型并且要以数组的形式传值,那么务必要进行Object修饰。

评分

参与人数 1技术分 +1 收起 理由
FFF + 1 赞一个!

查看全部评分

回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马