黑马程序员技术交流社区

标题: 一个神奇的结果…… [打印本页]

作者: 杨卫腾    时间: 2013-10-19 14:52
标题: 一个神奇的结果……
本帖最后由 杨卫腾 于 2013-10-19 20:40 编辑

  1. class Test3
  2. {
  3.         public static void main(String[] args)
  4.         {
  5.                 Test3 t = new Test3();
  6.                 t.method(null);
  7.         }

  8.         public void method(Object obj)
  9.         {
  10.                 System.out.println("Object");
  11.         }

  12.         public void method(String s)
  13.         {
  14.                 System.out.println("String");
  15.         }
  16. }
  17. // 以上编译通过,执行结果是String
  18. /*
  19. class Test4
  20. {
  21.         public static void main(String[] args)
  22.         {
  23.                 Test4 t = new Test4();
  24.                 t.method(null);
  25.         }

  26.         // 其基类都是Object
  27.         
  28.         public void method(Integer in)
  29.         {
  30.                 System.out.println("Object");
  31.         }

  32.         public void method(String s)
  33.         {
  34.                 System.out.println("String");
  35.         }
  36. }
  37. 编译失败:
  38. Test4.java:6: 错误: 对method的引用不明确, Test4中的方法 method(Integer)和Test4中
  39. 的方法 method(String)都匹配t.method(null);

  40. 如果改成一下方式:
  41. class Test5
  42. {
  43.         public static void main(String[] args)
  44.         {
  45.                 Test5 t = new Test5();
  46.                 t.method(null);
  47.         }
  48.         public void method(Fu fu)
  49.         {
  50.                 System.out.println("Fu");
  51.         }
  52.         public void method(Zi zi)
  53.         {
  54.                 System.out.println("Zi");
  55.         }
  56. }
  57. class Fu{}
  58. class Zi extends Fu
  59. {
  60.         Zi(){System.out.println("Zi show run")}
  61. }
  62. 编译通过,结果和Test3的如出一辙是 Zi.
  63. */
复制代码
请大家帮忙看看这是为什么?
作者: 上篮高手    时间: 2013-10-19 15:17
  1. class Jiujiu
  2. {
  3.         public static void main(String[] args)
  4.         {
  5.                 Jiujiu t = new Jiujiu();
  6.                 t.method(null);
  7.         }

  8.         public void method(Object obj)
  9.         {
  10.                 System.out.println("Object");
  11.         }
  12.         
  13.         public void method(File obj)
  14.         {
  15.                 System.out.println("File");
  16.         }
  17.         

  18.         public void method(String s)
  19.         {
  20.                 System.out.println("String");
  21.         }
  22. }
复制代码
以上代码又增加了一个重载
编译错误  报产生二义性。
总结: 对于有父子关系的 好像不会产生二义性
但是对于不存在父子关系的  就会报二义性的错误。
遇到这种情况 应该修正代码  尽量不要出现二义性问题。
作者: 風諾    时间: 2013-10-19 15:45
具体还真不知为什么这样
做了下实验,只得出来了些表面的结论
感觉JVM在调用方法的时候,当传入参数是null的时候,JVM总是默认把形参类型当做最低层的那个子类处理的
猜测这样处理可能存在什么好处或者避免了些麻烦,但是具体是什么,我确实想不出来,也暂时没有想到验证的方法
  1. class Test5
  2. {
  3.     public static void main(String[] args)
  4.     {
  5.             Test5 t = new Test5();
  6.             Fu fn = null;                //没有创建对象
  7.                    Zi zn = null;                //没有创建对象
  8.             Fu ff = new Fu();        //创建父类对象
  9.             Fu fz = new Zi();        //创建父类引用的子类对象
  10.             Zi zz = new Zi();        //创建子类对象
  11.             
  12.         //与引用变量类型有关
  13.             t.method(fn);        //输出Fu
  14.                 t.method(zn);        //输出Zi
  15.                 //与子类无关
  16.                 t.method(ff);        //输出Fu
  17.                 t.method(fz);        //输出Fu
  18.                 t.method(zz);        //输出Zi
  19.                
  20.                 //只执行那个形参是最低层子类对应的方法
  21.                 t.method(null);
  22.        
  23.     }
  24.     //确实是由继承引起的,但与方法顺序无关,换位置都是一样的结果,默认会执行那个形参是最小子类的方法  
  25.     public void method(Fu fu)
  26.     {
  27.              System.out.println("Fu");
  28.     }
  29.     public void method(Zi zi)
  30.     {
  31.             System.out.println("Zi");
  32.     }
  33.     //孙子的方法
  34.     public void method(Sun Sun)
  35.     {
  36.             System.out.println("Sun");
  37.     }
  38. }

  39. class Fu{}
  40. class Zi extends Fu
  41. {
  42.     Zi(){
  43.             System.out.println("Zi show run");
  44.     }
  45. }
  46. //再加个孙子类好了,哈哈
  47. class Sun extends Zi{}
复制代码

作者: 斗胆潇洒    时间: 2013-10-19 15:56
本帖最后由 斗胆潇洒 于 2013-10-19 16:00 编辑

java的重载方法,选择null实参的,是按照 就近原则
就像测试5,增加一 个孙子类,并添加一个重载的方法,
它会选择孙子的那个重载方法,
但是再增加一个儿子2号,同级别,两个距离等同,出现分歧,
对于Test3,也是String是Object的子,对于Test4,Integer和String应该是处于同级别

作者: 月夜之鬼魅    时间: 2013-10-19 16:34
本帖最后由 月夜之鬼魅 于 2013-10-19 16:37 编辑

这个例子证明:Java会按照就近原则,重载方法调用时会使用最符合参数类型的方法。
重载:方法名相同,参数表不同,返回值类型可以不同。调用时要给出明确参数并确定调用某一方法。在编译时,编译器会根据参数选择适当的方法,所以重载也叫编译时多态。
向上匹配原则:
如果方法的参数表中的数据类型和调用时给出的参数类型不尽相同时会根据向上匹配的就近原则。

作者: 周志龙    时间: 2013-10-19 18:37

如果楼主已经解惑,请将帖子改为提问结束
作者: 我能学编程吗    时间: 2013-10-19 19:40
本帖最后由 我能学编程吗 于 2013-10-19 19:48 编辑
  1. public static void main(String[] args) {
  2.                 Integer obj1 = null;
  3.                 String obj2 = null;
  4.                 method(obj1);
  5.                 method(getString());
  6.         }

  7.         public static void method(Integer i) {
  8.                 System.out.println("Interger");
  9.         }

  10.         public static void method(String s) {
  11.                 System.out.println("String");
  12.         }
  13.         
  14.         public static String getString() {
  15.                 return null;
  16.         }
复制代码
我说说我的看法:
代码改成如上:不论参数传obj1还是obj2都能得到正确的输出。一般调用方法传参时要么是传一个变量,变量有声明具体类型,要么是调用一个方法,但是这个方法有具体的返回值类型也不会错。
楼主是主直接传了一个null进去,这样的情况一般很少会用到。这里你方法有重载,你传null进行是想干嘛,你是想调用哪个方法呢?别人读起来就不好理解。你直接传null,就算不报错,就算你能调用到任何一个重载的方法都是不符合人的思维习惯的,所以人们不会这么搞,所以这个问题可以略过不研究为什么了,没必要。




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2