zoukankan      html  css  js  c++  java
  • 常见Java面试题 – 第三部分:重载(overloading)与重写(overriding)

    ImportNew注: 本文是ImportNew编译整理的Java面试题系列文章之一。你可以从这里查看全部的Java面试系列。

    这篇文章介绍的常见面试题是关于重载(overloading)方法和重写(overriding)方法的。

    Q.下面代码片段的输出结果是什么?

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    public class MethodOverrideVsOverload {
     
     public boolean equals( MethodOverrideVsOverload other ) {
         System.out.println("MethodOverrideVsOverload equals method reached" );
         return true;
       }
     
     public static void main(String[] args) {
      Object o1 = new MethodOverrideVsOverload();
      Object o2 = new MethodOverrideVsOverload();
     
      MethodOverrideVsOverload o3 = new MethodOverrideVsOverload();
      MethodOverrideVsOverload o4 = new MethodOverrideVsOverload();
     
      if(o1.equals(o2)){
       System.out.println("objects o1 and o2 are equal");
      }
     
      if(o3.equals(o4)){
       System.out.println("objects o3 and o4 are equal");
      }
     }
    }

    A.输出结果是:

    MethodOverrideVsOverload equals method reached

    objects o3 and o4 are equal

    这个问题考察了哪些概念呢?

    • Java语言中,一个类只能从一个类中继承出来(也就是,单继承结构),如果没有显式的标明所继承自的类,那么自动继承自Object对象。
    • 大多数的非final对象类方法都会被子类重写(overridden):

    public boolean equals(Object obj); // make note of this method

    public int hashCode();

    public String toString();

    • 重载方法在编译时起作用(例如,静态绑定),重写方法在运行时起作用(例如,动态绑定)。静态绑定意味着JVM在编译时决定调用的类或方法。而动态绑定时,JVM是在运行时决定调用的类或方法。动态绑定设计是多态的基础。更多了解编译时和运行时.
    • 子类中重写父类的对应方法必须遵循下面的规则:
    参数 不可变(译者注:包括参数类型和个数)。
    返回类型 不可变,除了协变返回类型或其子类型(covariant (subtype) returns)。
    异常 子类中可以抛出更少的异常,但绝对不能抛出父类中没有定义的已检查异常。
    访问权限 比父类中对应方法更宽松。
    调用 运行时(也就是动态绑定),根据对象类型来决定调用的具体方法。

    现在,再回头看上面的代码,MethodOverrideVsOverload  类中的”equals(MethodOverrideVsOverload other)” 方法并没有重写Object类中的”public boolean equals(Object obj)” 方法。这是因为其违背了参数规则,其中一个是MethodOverrideVsOverload 类型,而另一个是Object类型。因此,这两个方法是重载关系发生在编译时),而不是重写关系

    因此,当调用o1.equals(o2)时,实际上调用了object类中的public boolean equals(Object obj)方法。这是因为在编译时,o1和o2都是Object类型,而Object类的equals( … )方法是比较内存地址(例如,Object@235f56和Object@653af32)的,因此会返回false。

    当调用o3.equals(o4)时,实际上调用了MethodOverrideVsOverload 类中的equals( MethodOverrideVsOverload other )方法。这是因为在编译时,o3和o4都是MethodOverrideVsOverload类型的,因此得到上述结果。

    接下来还可以怎么提问呢?

    Q.那怎么解决上面的那个问题呢?

    A.在Java5中,新增了注解,其中包括很好用的编译时注解(compile time annotations)@override,来保证方法正确的重写了父类方法。如果在上面的代码中添加了注解,那么JVM会抛出一个编译错误。

    因此,解决的方法就是给MethodOverrideVsOverload  类的boolean equals( MethodOverrideVsOverload other )方法添加@override注解。这样的话编译时就会有错误抛出来提示开发者某个方法没有正确的重写父类方法。之后,还需要修改方法的参数,将其从MethodOverrideVsOverload变成Object,具体如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    public class MethodOverrideVsOverload {
     
     @Override
     public boolean equals( Object other ) {
         System.out.println("MethodOverrideVsOverload equals method reached" );
         return true;
     }
     
     public static void main(String[] args) {
      Object o1 = new MethodOverrideVsOverload(); //during compile time o1 is of type Object
                                                  //during runtime o1 is of type MethodOverrideVsOverload
      Object o2 = new MethodOverrideVsOverload(); //during compile time o2 is of type Object
                                                  //during runtime o2 is of type MethodOverrideVsOverload
     
      MethodOverrideVsOverload o3 = new MethodOverrideVsOverload(); //o3 is of type MethodOverrideVsOverload
                                                                    // during both compile time and runtime
      MethodOverrideVsOverload o4 = new MethodOverrideVsOverload(); //o4 is of type MethodOverrideVsOverload
                                                                    // during both compile time and runtime
     
      if(o1.equals(o2)){
       System.out.println("objects o1 and o2 are equal");
      }
     
      if(o3.equals(o4)){
       System.out.println("objects o3 and o4 are equal");
      }
     
     }
     
    }

    输出为:

    MethodOverrideVsOverload equals method reached

    objects o1 and o2 are equal

    MethodOverrideVsOverload equals method reached

    objects o3 and o4 are equal

    上面的代码中,运行时equals方法正确的重写了Object中的相应方法。这是一个比较容易混淆的问题,面试的时候需要很详尽的解释相关的概念。

     扩展阅读:

    英文原文: Java Success,编译:ImportNew - 郑雯

    译文链接:http://www.importnew.com/2228.html

  • 相关阅读:
    [kuangbin带你飞]专题十二 基础DP1
    bits/stdc++.h
    第七届 山东省ACM Execution of Paladin(水题)
    poj 1523 SPF【点双连通求去掉割点后bcc个数】
    hdoj 5112 A Curious Matt
    【转】我,一个写代码的
    poj 3177 Redundant Paths【求最少添加多少条边可以使图变成双连通图】【缩点后求入度为1的点个数】
    数据结构第二次上机实验【链表实现多项式的加法和乘法】
    hdoj 4612 Warm up【双连通分量求桥&&缩点建新图求树的直径】
    hdoj 3849 By Recognizing These Guys, We Find Social Networks Useful【双连通分量求桥&&输出桥&&字符串处理】
  • 原文地址:https://www.cnblogs.com/daichangya/p/12958975.html
Copyright © 2011-2022 走看看