再谈Java中的覆盖(Overriding)与重载(Overloading)

Overriding vs Overloading in Java 中,我们简单介绍了Java中的OverridingOverloading ,下面我们就此话题继续探讨:

问题一:什么是静态绑定?

答: 在JAVA源码编译阶段,JVM将方法调用与实际方法进行绑定的过程,这就是静态绑定,我们常见的方法重载绑定( method Overloading binding )就是静态绑定。

问题二:什么是动态绑定?

答: 覆盖方法绑定(Binding of overridden methods)就是我们常见的动态绑定,即编译阶段只确定引用类型对象,运行时生成实际对象类型,并将对象引用指向运行时生成对象的内存堆地址。

问题三:你可以 override静态方法么?

答案:否,static方法属于类方法,属于类级别,而非对象实例级别,类方法是在类的加载机制的编译阶段就会执行的方法,我们上一章说过,Overriding涉及一个运行时概念,即我们常见的动态绑定机制,所以我们是无法通过Override静态方法来达到预期效果的。当然,如果你在子类中Override父类中相同方法签名的方法,编译期是不会报错的,但是却无法得到预期的Overriding行为的,下面我们示例说明:

父类 Dog 中定义静态方法 eat

class Dog {
    public void bark() {
        System.out.println("woof");
    }

    public void bark(int num) {
        for (int i = 0; i < num; i++) {
            System.out.println("woof");
        }
    }

    **static void eat(){
        System.out.println("Dog eat");
    }**
}

子类 HoundOverride 父类中的 eat 方法

class Hound extends Dog {
    public void bark() {
        System.out.println("bowl");
    }
    static void eat(){
        System.out.println("Hound eat");
    }
}

验证对静态方法的 Override的效果

public class OverrideAndOverload {
    public static void main(String[] args) {
        Dog a = new Hound();
        a.bark();
        a.bark(1);
        **a.eat();**
    }
}

执行结果如下:

bowl
woof
Dog eat

从上面的执行结果我们可以看到,对静态方法的Override并没有达到预期效果,这就是我们常见的方法隐藏 method hiding

问题四:可以覆盖(Override)私有(private)方法和final方法么?

答:私有方法(private)对子类不可见,因此,你无法覆盖私有方法,final关键词修饰的方法或变量表明方法或变量不可变,即你无法重新修改目标对象,因此你无法覆盖(Override)方法

问题五:什么是协变返回类型?

答:如果子类中覆盖(overrides)了父类中的相关方法,那么子类方法的返回类型可以是父类方法中返回类型的子类,下面我们代码示例:

父类 Base 方法 m 返回类型为A,子类 Sub 覆盖了方法 m,但返回类型B(B是A的子类),这就是我们Overriding中的协变返回类型。

class A {
}

class B extends A {

}

class Base {
    public A m() {
        System.out.println("In BaseClass method");
        return new A();
    }
}

class Sub extends Base {
    public B m() {
        System.out.println("In SubClass method");
        return new B();

    }
}

public class CovariantReturnTypeTest {
    public static void main(String[] args) {
        Base b = new Sub();
        b.m();
    }
}

运行结果:

In SubClass method

问题六:以下代码输出结果?

import java.io.IOException;


public class MethodOverrdingTestMain {
    public static void main(String[] args) {
        B b = new B();

        try {
            b.method();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}


class A {
    public void method() **throws IOException** {
    }
}


class B extends A {
    public void method() **throws Exception** {
    }
}

输出

**compile time error**

子类覆盖(Override)方法抛出的异常《= 父类方法抛出的异常,即子类抛出的异常可以缩小或不抛出异常,但不能新增或者扩大 **checked
Exception**

问题七:以下代码输出结果?

class Base {
    **public** A m() {
        System.out.println("In BaseClass method");
        return new A();
    }
}

class Sub extends Base {
    **protected** B m() {
        System.out.println("In SubClass method");
        return new B();

    }
}

public class CovariantReturnTypeTest {
    public static void main(String[] args) {
        Base b = new Sub();
        b.m();
    }
}

结果:

compiler time error

子类覆盖(Override)方法的访问修饰符 》= 父类方法访问修饰符


  • 覆盖(Overriding)使用规范
方法参数 完全一致
返回类型 保持一致或者协变返回类型
访问修饰符 子类访问修饰符大于等于父类访问修饰符
异常 子类异常必须小于父类异常
构造方法 无法覆盖
静态方法 无法覆盖
final方法 无法覆盖

  • 重载(Overloading)使用规范
参数个数 重载方法参数个数不同
参数类型 重载方法参数类型不同
返回类型 可以修改返回类型,但需注意重载情况不能出现方法签名相同但返回类型不同
参数顺序 如果各个参数数据类型不同,那么参数顺序变化也是合法的方法重载
构造函数 可以重载

原文链接:https://java2blog.com/method-overloading-and-overriding-interview-questions-in-java/

你可能感兴趣的:(Java)