• 2004-06-24

    重载游戏

    Tag:向上走

    版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明
    http://www.blogbus.com/dreamhead-logs/234651.html

    看看下面这个程序,在运行之前,先估计一下结果是什么。
    public class OverloadGame {
        public static void main(String[] args) { 
            test(null);
        }

        public static void test(Object o) {
            System.out.println("test Object");
        }

        public static void test(Object[] oa) {
            System.out.println("test Object array");
        }
    }

    先跟着我往歧途上走一段。
    这是一个演示重载用法的小程序,重载的精华就在于不同的方法可以使用相同方法名,从某种意义上来说,这也是一种多态。JUnit中一大堆assert方法应该算是重载用法的一次集中展示,正是有了强大的重载功能,当我们写下这样的代码:
        assertEquals(expected, actual);
    我们通常不会去仔细考虑,expected和actual究竟是对象还是基本类型。

    在Java中,区分重载方法是在编译阶段完成的,所以,了解一下Java代码如何编译,上面的问题就可以迎刃而解。关于Java语言的一切,还有谁比Java语言规范更有说服力呢?Java语言规范的15.12节讨论的就是如何确定调用哪个方法。
    让我们直取要害,看看如何区分重载方法。
    在确定了有多个可用的方法之后,Java语言确定具体方法时,使用了一条“most specific method”的规则从众多的候选方法中选择最合适的一个。如果一个参数能够匹配多个方法的声明,那就越贴切越好,比如一个Circle对象,遇到的方法有用自己直接父类Shape,也有用Object,既然自己和自己的父类这么近,就不必麻烦老祖宗Object了。基本上可以用“有子类不用父类”简单的概括这以规则。
    在参数类型与众多方法声明的参数类型无法准确匹配的时候,这个规则意义更大,一旦可以准确匹配,那那个方法当然就是首选了。

    回头看看,前面的程序,null匹配谁更合适呢?
    在Java中,null可以代表任何对象,所以它匹配Object一点问题都没有,至于Object数组,算了吧,我要一个人,不用一个连。

    说一千,道一万,不如实际跑一遍:
        test Object array
    怎么会这样?前面振振有辞的分析,怎么没有换来理想的结果?

    把Java语言规范翻到第十章《数组》,这章开篇写道:“在Java程序设计语言中,数组就是对象。”
    不错,数组就是对象,由此得出结论Object[]是Object的子类,我知道,从情感上来说,这很难让人接受,人多势众反而不如原先地位高。虽然心理上很难接受,但这是事实。
    接下来的就好解释了,前面说过,有子类可以匹配,就不会麻烦父类,因为Object[]是Object的子类,所以,编译时,优先选择Object[],而非前面预期的Object。

    这个游戏还可以接着往下做,我们可以尝试在类中再加入一个方法:
        public static void test(String oa) {
            System.out.println("test String");
        }
    不用运行,因为编译时就会出错。
    根据前面的分析,Object首先出局,就看Object[]和String那个更适合null的发挥,遗憾的是,它们俩根本不是一路人,null也不知道跟谁走更合适了,只好报错,于是,著名的ambiguous呈现在我们面前。

    分享到:

    历史上的今天:

    引用地址:

    评论

  • 呵呵,写的不错。不过我认为“有子类不用父类”这个总结可能会让某些人产生误解,我刚才差点也误解了:)就像文中说的,重载是在编译阶段完成的,因此运行时是按照声明的对象类型来确定调用某方法。即使是子类对象,但是如果声明为父类对象,调用的还是父类当参数的方法。




    举个很简单的例子,把main里面的test(null),改为




    Object obj = null;


    test(obj);


    回复crmky说:
    多谢你的指正!实际上这个情况我当时也尝试过,只是写这篇blog的时候,没有一下子想起来,所以,就把它忽略了。再次感谢你!
    2004-06-24 21:58:54