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

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 夏天 初级黑马   /  2012-9-21 00:53  /  1513 人查看  /  7 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 夏诗瑶 于 2012-9-21 01:34 编辑

//写一个程序,这个程序能够根据用户提供的类名,去执行该类中的main方法。
//张老师的方法如下:
import java.lang.reflect.Method;
class DefineMain {
public static void main(String[] args) {
  System.out.println("我是自定义类的主方法" + args[0]);
}
}
public class Test {
public static void main(String[] args) throws Exception {
  // DefineMain.main(new String[]{"abc"});// 自定义方法之前是这样调用的
  String str = args[0];// 如果没有传参数进来,则不能这么赋值
  Method mainMethod = Class.forName(str).getMethod("main", String[].class);
  mainMethod.invoke(null, new String[] { "abc" });//★★★★★★
//我的疑问一是需要的是String[].class 也就是需要String类型的数组,传递的参数是new String[] { "abc" )就不可以了呢?虽然老师有解释,我认为不清楚
}
}


我的疑问二,我自己还有个思路,事实证明可行,可不知道为什么要用上面的方法呢??
Method mainMethod = MyDefineMain.class.getMethod("main", String[].class);
mainMethod.invoke(null, (Object) new String[] { "abc" });//这里不考虑上面的问题,我的意思就是 干嘛要弄那么麻烦,又是args[0]了,又是运行Test里的main方法时,加个全路径的类名参数了。。。。

7 个回复

正序浏览
本帖最后由 马镱洵 于 2012-9-21 03:16 编辑

"//我的疑问一是需要的是String[].class 也就是需要String类型的数组,传递的参数是new String[] { "abc" )就不可以了呢?虽然老师有解释,我认为不清楚}"

不是不可以,而是因为你没有给你的Test的类的main()方法传递参数,传递参数要这样传递,假设你用的eclipse:


如果你是在命令行运行Test类,那么就这样传递参数:
java Test DefineMain
这样你的程序就不会有问题了.



"我的疑问二,我自己还有个思路,事实证明可行,可不知道为什么要用上面的方法呢??
Method mainMethod = MyDefineMain.class.getMethod("main", String[].class);
"

Method mainMethod = MyDefineMain.class.getMethod("main", String[].class);
这样写法就不科学了,你是自己知道你有个MyDefineMain类,那可以这样写.要是你不知道你有MyDefineMain类呢,那你如何获得你不知道类名的类的字节码信息呢.那就只有用Class.forName()方法了啊,这样可以在运行时,自己写"包名.类名"的完全限定名,就可以随意取得任何类的字节码信息了.



"mainMethod.invoke(null, (Object) new String[] { "abc" });//这里不考虑上面的问题,我的意思就是 干嘛要弄那么麻烦,又是args[0]了,又是运行Test里的main方法时,加个全路径的类名参数了。。。。"

public Method getMethod(String name, Class<?>... parameterTypes) throws NoSuchMethodException, SecurityException
看吧,第二个参数是要求你传入一个Class类型的可变参数...
此处省略1000字,不废话了,直接说重点,这里有个细节要注意:
只要是在反射中调用方法,若方法中实际传入的参数的类型是数组或可变参数,这就要分两种情况来讨论:
1 如果参数是基本数据类型的数组或可变参数,就可以不用Object数组来包装(也不必要将最后结果强转为Object),例如:
mainMethod.invoke(null, new int[] { 222 });
2 如果参数是引用类型的数组或可变参数,就必须要用Object数组来包装(也可以将最后结果强转为Object),例如:
mainMethod.invoke(null, new Object[] { new Integer[] { 222 } });

mainMethod.invoke(null,  (Object) new Integer[] { 222 });

人家就是要考验你们对从命令行传入参数的技能掌握的如何,对Class.forName()方法掌握的如何,所以才会这样玩.
现在把给你修改后的代码发出来:
  1. import java.lang.reflect.InvocationTargetException;
  2. import java.lang.reflect.Method;

  3. class DefineMain {

  4. public static void main(String[] args) {
  5. System.out.println("我是自定义类的主方法" + args[0]);
  6. }

  7. }

  8. public class Test {

  9. public static void main(String[] args) {
  10. // DefineMain.main(new String[]{"abc"});// 自定义方法之前是这样调用的
  11. String str = args[0];// 如果没有传参数进来,则不能这么赋值
  12. Method mainMethod = null;
  13. try {
  14. mainMethod = Class.forName(str).getMethod("main", String[].class);
  15. mainMethod.invoke(null, new Object[] { new String[] { "abc" } });
  16. // ★★★★★★
  17. // 我的疑问一是需要的是String[].class 也就是需要String类型的数组,
  18. // 传递的参数是new String[] {"abc")就不可以了呢?虽然老师有解释,我认为不清楚}
  19. } catch (SecurityException e) {
  20. e.printStackTrace();
  21. } catch (NoSuchMethodException e) {
  22. e.printStackTrace();
  23. } catch (ClassNotFoundException e) {
  24. e.printStackTrace();
  25. } catch (IllegalArgumentException e) {
  26. e.printStackTrace();
  27. } catch (IllegalAccessException e) {
  28. e.printStackTrace();
  29. } catch (InvocationTargetException e) {
  30. e.printStackTrace();
  31. }
  32. }

  33. }
复制代码
回复 使用道具 举报
夏天 初级黑马 2012-9-21 02:02:33
7#
张 涛 发表于 2012-9-21 01:59
这里是要用test类中的main方法去调用DemoMain类中的main方法。

你说传入一个全路径的类名参数,要传到test ...

OK,明白了,这其实也是简单的封装。
回复 使用道具 举报
这里是要用test类中的main方法去调用DemoMain类中的main方法。

你说传入一个全路径的类名参数,要传到test类中main方法中,只能通过参数传,参数就是args了。

如果你说在test类的main方法中定义一个,如果要调用其他类的main方法怎么办?再修改main中的定义吗?

所以是通过传入参数来确定调用哪个类的main方法。
回复 使用道具 举报
张 涛 发表于 2012-9-21 01:29
1.参数是String[],字符串数组没错。

2.在实现invoke方法时,第二个参数在jdk1.5中采用的是可变参数,如果 ...

我又重新描述问题了,麻烦你重新看下。。
回复 使用道具 举报
1.参数是String[],字符串数组没错。

2.在实现invoke方法时,第二个参数在jdk1.5中采用的是可变参数,如果执行时是按照1.5的jdk,那程序就没错。

3.而在jdk1.4中,没有可变参数,他采用的方法是第二个参数是object数组,即把参数打包成object数组,方法接受到数组后,再拆包拿出各参数。

4.jdk1.5为了兼容jdk1.4,第二个参数传入objcet数组他也会支持。

5.这里传入string数组,string数组也是object数组,jdk会当作1.4的参数传进来,所以会用1.4的方式解决,拆开数组,参数就变成了一个个字符串,那么参数类型就不对了。

-------------------------------------------------------------------------------------------------------------

第二个疑问没看懂。。。。

你下面的代码是把sting数组转化为一个object,作为参数传入,因为不是object数组,所以不会当作1.4处理,使用1.5处理就对了。
回复 使用道具 举报
何小红 发表于 2012-9-21 01:05
还卡在反射这儿呢? 我也有好多问题不懂

嗯,脚踏实地,慢慢来,进不了14,我就进15了。
回复 使用道具 举报
还卡在反射这儿呢? 我也有好多问题不懂
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马