看了张孝祥老师的 23_对接收数组参数的成员方法进行反射 这一节,关于在调用invoke时参数会自动解包的问题,注:此篇文档是个人见解加个人实验结果,大家可以提出不同意见,共同进步
视频里只讲解了Main方法里的(String[] args)函数,我在想为什么会拆包?到底有哪些都会自动拆包呢,自己写的类,基础类型,还有一些Java提供的类都会吗?
带着这些疑问,首先看API
1.为什么会自动拆包
public Object invoke(Object obj, Object... args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException对带有指定参数的指定对象调用由此 Method 对象表示的底层方法。个别参数被自动解包,以便与基本形参相匹配,基本参数和引用参数都随需服从方法调用转换。 如果底层方法是静态的,那么可以忽略指定的 obj 参数。该参数可以为 null。
如果底层方法所需的形参数为 0,则所提供的 args 数组长度可以为 0 或 null。
我们注意到个别参数被自动解包,再看上面invoke的参数(object obj,Object... args)注意这里是Object,其实也就不难理解为什么会自动解包了
因为Java1.5开始有可变参数的特性,当你放入一个String[] args的时候,那么编译器怎么知道你是要放入一个String[]对象,还是多个String对象呢.
所以编译器默认就把它进行解包,解成一个个String对象以便于基本形参相匹配了.
所以说我们在传入参数的时候可以用(Object)new String[]("123,"456","789")告诉编译器我只传一个Object,
另外一种就是骗过编译器new Object[](new String[]("123","456","789"))编译器拆了之后还是一个String[]数组.
2.哪些会自动拆包
我实验的结果是,除了基本数据类型数组,其他统统要拆包,废话不说上代码
- import java.lang.reflect.Method;
- import java.lang.Class;
- import java.lang.Exception;
- class MainReflect
- {
- public static void main(String[] args) throws Exception{
- Method method1 = Class.forName("IntReflect").getMethod("intParams",int[].class);
- Method method2 = Class.forName("StringReflect").getMethod("strParams",String[].class);
- Method method3 = Class.forName("IntegerReflect").getMethod("integerParams",Integer[].class);
- Method method4 = Class.forName("ObjectReflect").getMethod("objParams",NewObject[].class);
- /*第一个invoke编译时系统是不会提示的,运行时也不会报错,正常输出123",<font color="#ff0000">所以基本数据类型的数组是不解包的</font>*/
- method1.invoke(null,new int[]{1,2,3});
- /*下面三个编译时
- MainReflect.java:12: 警告:最后一个参数使用了不准确的变量类型的 varargs 方法的非
- varargs 调用;对于 varargs 调用,应使用 java.lang.Object对于非 varargs 调用,
- 应使用 java.lang.Object[],这样也可以抑制此警告
- 其实看到这个提示我们就该明朗,我们用的是varargs调用,应该使用java.lang.Object,系统认不清
- 你的参数
- 我们再看编译时错误
- Exception in thread "main" java.lang.IllegalArgumentException: wrong number of a
- rguments
- 因为你只需要一个Integer对象[]对象,而你的方法拆成了三个Integer,不合法的参数异常.
- */
- method2.invoke(null,new String[]{"111","222","333"});
- method3.invoke(null,new Integer[]{10,20,30});
- method4.invoke(null,new NewObject[]{new NewObject(),new NewObject()}); //<font color="#ff0000">自定义的类一样自动解包</font>
-
- }
- }
- class IntReflect
- {
- public static void intParams(int[] args){
- for(int i : args){
- System.out.println(i);
- }
- }
- }
- class IntegerReflect
- {
- public static void integerParams(Integer[] args){
- for(Integer i : args){
- System.out.println(i);
- }
- }
- }
- class StringReflect
- {
- public static void strParams(String[] args){
- for(String str : args){
- System.out.println(str);
- }
- }
- }
- class ObjectReflect
- {
- public static void objParams(NewObject[] objs){
- for(NewObject obj : objs){
- obj.open();
- }
- }
- }
- class NewObject
- {
- public void open(){
- System.out.println("hello");
- }
- }
复制代码 好了,以上是我的总结,欢迎大家讨论.
|
|