• Java重载方法如何竞争


    突然想起以前遇到的一道笔试题,题目大概是这样子的

    // 父类
    public class Father {
    }
    
    // 子类
    public class Son extends Father {
    }
    
    // 调用方
    public class Main {
        private static void run(Father father) {
            System.out.println("Father");
        }
        
        private static void run(Son son) {
            System.out.println("Son");
        }
        
        public static void main(String[] args) {
            Father son = new Son();
            run(son);
        }
    }
    

    问:以上代码的运行结果是什么?

    我们先把这个题目放一边,现在把这个问题扩展一下

    public class Main { 
        // 重载1
        private static void run(int param) {
            System.out.println("int");
        }
        
        // 重载2
        private static void run(long param) {
            System.out.println("long");
        }    
        
        // 重载3
        private static void run(Integer param) {
            System.out.println("Integer");
        }
        
        // 重载4
        private static void run(Long param) {
            System.out.println("Long");
        }
        
        // 重载5
        private static void run(float param) {
            System.out.println("float");
        }
        
        // 重载6
        private static void run(double param) {
            System.out.println("double");
        }
        
        // 重载7
        private static void run(Object param) {
            System.out.println("Object");
        }
        
        // 重载8
        private static void run(int... param) {
            System.out.println("int...");
        }
        
        public static void main(String[] args) {
            run(1);
        }
    }
    
    • 以上的代码运行结果是什么?
    • 如果把重载1方法注释掉,运行结果是什么?
    • 如果把重载1、2、3、4这4个方法注释掉,运行结果是什么?

    以上的8个重载的方法,在调用者看来,如果传入一个“范围”较小的参数,比如传入参数1,好像所有方法在单独情况下都可以调用,但是在所有方法都存在的情况下,又不知道要怎么选择。调用重载方法遵循的优先级从高到低如下:

    (1)精确匹配

    比如传入了参数1,默认情况1是int类型的数据,那么就会调用run(int param)方法,这个没有什么疑问。而一开始的面试题也是这种情况,变量son是一个Father类型的对象,会调用run(Father father)方法从而运行结果是Father。

    (2)如果是基本类型(8种),向上转为更大范围

    我们都知道一个int类型的数据和一个long类型的数据运算,会先把int类型的数据隐式转换为long类型,再进行运行,结果得到一个long类型;一个long类型和一个float类型做运算,long类型会先转换为float类型;一个float类型和一个double类型运算,float类型会先转换为double型。重载方法也是同样的道理,如果没有精确的类型,会向上找,如果把重载1方法注释掉之后,会调用run(long param),如果也没有重载2,就会调用run(float param),以此类推。

    (3)通过自动拆箱和装箱

    假如重载1、2、5、6都被注释了,就会找自动装箱的参数,int自动装箱是Integer,也就是会调用run(Integer param)。

    (4)通过子类向上继承路线依次匹配

    比如以上的例子注释掉重载1、2、3、5、6之后,调用的是run(Object param),而不是run(Long param),因为Long不是Integer的父类。

    (5)通过可变参数匹配

    如果1、2、3、4条规则都没法匹配到方法,就会匹配可变参数,可变参数的竞争优先级是很低的。比如以上例子把重载1、2、3、5、6、7都注释掉,就会调用run(int... param)方法。

    再看另一个例子

    public class Main {
        private static run(int param1, Integer param2) {}
        private static run(Integer param1, int param2) {}
        
        public static void main(String[] args) {
            run(1, 2);
        }
    }
    

    以上代码的运行结果是什么?

    其实,上面的代码会编译报错,因为编译器不知道调用的时候到底是要把1自动装箱还是要把2自动装箱,调用的时候需要显式传入Integer类型的对象,而不是让编译器进行自动装箱操作,比如调用第一个方法时可以用run(1, Integer.valueOf(2)),同理,想要调用方法2时用run(Integer.valueOf(1), 2)。

    说了那么多其实我们了解就行了,建议在实际的开发中尽量避免出现这样的重载方法,可以根据参数的不同改用不一样的方法名,因为这种写法其实和i++ + ++i一样会使得代码的可读性极差。

  • 相关阅读:
    Eclipse创建Maven Web项目 + 测试覆盖率 + 常见问题(2015.07.14——湛耀)
    JAVA面试题——JAVA编程题1(2015.07.22)
    Spring 国际化
    BeanPostProcessor 的使用,实现在对象初始化之前或者之后对对象进行操作
    spring 的配置 bean>>property>>name属性
    文件保存
    Spring-demo1(初学者的尝试,2015.03.19)
    新花生壳内网版2.3 + Tomcat7 搭建自己的网站(2015.01.21)
    (原)Struts 相关资源下载
    Xilinx 7 series FPGA multiboot技术的使用(转)
  • 原文地址:https://www.cnblogs.com/spareyaya/p/12804079.html
Copyright © 2020-2023  润新知