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

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 杨卫腾 中级黑马   /  2013-10-19 14:52  /  1409 人查看  /  6 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 杨卫腾 于 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. */
复制代码
请大家帮忙看看这是为什么?

评分

参与人数 1技术分 +1 收起 理由
特殊服务 + 1

查看全部评分

6 个回复

倒序浏览
  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. }
复制代码
以上代码又增加了一个重载
编译错误  报产生二义性。
总结: 对于有父子关系的 好像不会产生二义性
但是对于不存在父子关系的  就会报二义性的错误。
遇到这种情况 应该修正代码  尽量不要出现二义性问题。

评分

参与人数 1技术分 +1 收起 理由
特殊服务 + 1

查看全部评分

回复 使用道具 举报
具体还真不知为什么这样
做了下实验,只得出来了些表面的结论
感觉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{}
复制代码

评分

参与人数 1技术分 +1 收起 理由
特殊服务 + 1

查看全部评分

回复 使用道具 举报
本帖最后由 斗胆潇洒 于 2013-10-19 16:00 编辑

java的重载方法,选择null实参的,是按照 就近原则
就像测试5,增加一 个孙子类,并添加一个重载的方法,
它会选择孙子的那个重载方法,
但是再增加一个儿子2号,同级别,两个距离等同,出现分歧,
对于Test3,也是String是Object的子,对于Test4,Integer和String应该是处于同级别
回复 使用道具 举报
本帖最后由 月夜之鬼魅 于 2013-10-19 16:37 编辑

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

评分

参与人数 1技术分 +1 收起 理由
特殊服务 + 1

查看全部评分

回复 使用道具 举报

如果楼主已经解惑,请将帖子改为提问结束
回复 使用道具 举报
本帖最后由 我能学编程吗 于 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,就算不报错,就算你能调用到任何一个重载的方法都是不符合人的思维习惯的,所以人们不会这么搞,所以这个问题可以略过不研究为什么了,没必要。
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马