ImportNew注: 本文是ImportNew编译整理的Java面试题系列文章之一。你可以从这里查看全部的Java面试系列。
这篇文章介绍的常见面试题是关于重载(overloading)方法和重写(overriding)方法的。
Q.下面代码片段的输出结果是什么?
1 public class MethodOverrideVsOverload { 2 3 public boolean equals( MethodOverrideVsOverload other ) { 4 System.out.println("MethodOverrideVsOverload equals method reached" ); 5 return true; 6 } 7 8 public static void main(String[] args) { 9 Object o1 = new MethodOverrideVsOverload(); 10 Object o2 = new MethodOverrideVsOverload(); 11 12 MethodOverrideVsOverload o3 = new MethodOverrideVsOverload(); 13 MethodOverrideVsOverload o4 = new MethodOverrideVsOverload(); 14 15 if(o1.equals(o2)){ 16 System.out.println("objects o1 and o2 are equal"); 17 } 18 19 if(o3.equals(o4)){ 20 System.out.println("objects o3 and o4 are equal"); 21 } 22 } 23 }
A.输出结果是:
MethodOverrideVsOverload equals method reached
objects o3 and o4 are equal
这个问题考察了哪些概念呢?
public boolean equals(Object obj); // make note of this method
public int hashCode();
public String toString();
参数 | 不可变(译者注:包括参数类型和个数)。 |
返回类型 | 不可变,除了协变返回类型或其子类型(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注解。这样的话编译时就会有错误抛出来提示开发者某个方法没有正确的重写父类方法。之后,还需要修改方法的参数,将其从 Object变成MethodOverrideVsOverload,具体如下:
1 public class MethodOverrideVsOverload { 2 3 @Override 4 public boolean equals( Object other ) { 5 System.out.println("MethodOverrideVsOverload equals method reached" ); 6 return true; 7 } 8 9 public static void main(String[] args) { 10 Object o1 = new MethodOverrideVsOverload(); //during compile time o1 is of type Object 11 //during runtime o1 is of type MethodOverrideVsOverload 12 Object o2 = new MethodOverrideVsOverload(); //during compile time o2 is of type Object 13 //during runtime o2 is of type MethodOverrideVsOverload 14 15 MethodOverrideVsOverload o3 = new MethodOverrideVsOverload(); //o3 is of type MethodOverrideVsOverload 16 // during both compile time and runtime 17 MethodOverrideVsOverload o4 = new MethodOverrideVsOverload(); //o4 is of type MethodOverrideVsOverload 18 // during both compile time and runtime 19 20 if(o1.equals(o2)){ 21 System.out.println("objects o1 and o2 are equal"); 22 } 23 24 if(o3.equals(o4)){ 25 System.out.println("objects o3 and o4 are equal"); 26 } 27 28 } 29 30 }
输出为:
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 - 郑雯