覆盖和重载方法

时间:2019-06-11 02:40:43

标签: java methods software-design

“投射会影响编译时重载方法的选择,但不会覆盖重载方法”是什么意思?

我阅读了以下有关“重写的方法和动态绑定”(https://www.oreilly.com/library/view/learning-java-4th/9781449372477/ch06s01.html)的文章,但我听不懂最后一段

“在上一节中,我们提到了重载方法是由编译器在编译时选择的。另一方面,重写方法是在运行时动态选择的。即使我们创建子类的实例,我们的代码也永远不会如前所述(也许是一个通过网络加载的新类),它包含的所有替代方法都可以在运行时找到并使用,从而替换上次编译代码时存在的方法。

相反,如果我们创建一个新的类来实现一个额外的,更特定的,重载的方法,并用它替换我们的类路径中的已编译类,则我们的代码将继续使用其最初发现的实现。这种情况将一直持续到我们将代码与新类一起重新编译。这样做的另一个效果是,强制转换(即,明确地告诉编译器将对象视为其可分配类型之一)在编译时会影响重载方法的选择,但不会覆盖重写的方法。”

我无法理解“ Casting”这一行:“这的另一个影响是强制转换(即,明确地告诉编译器将对象视为其可分配类型之一)在编译时会影响重载方法的选择,但不会被覆盖方法。”

2 个答案:

答案 0 :(得分:2)

该行指的是

  
      方法的
  • 重载版本是在编译时根据传递的参数的编译时类型选择的;而
  •   
  • 在运行时根据调用每个方法的对象的类别选择覆盖的方法。
  •   

要了解这种区别,请考虑这样一种情况,即您同时具有覆盖和重载。

public class Person {
}
---------------------------------------------------------
public class Postman extends Person {
}
---------------------------------------------------------
public class Dog {
    public void barkAt(Person p) {
        System.out.println("Woof woof");
    }

    public void barkAt(Postman p) {
        System.out.println("Grrrr");
    }
}
---------------------------------------------------------
public class Rottweiler extends Dog {
    @Override
    public void barkAt(Person p) {
        System.out.println("I'm going to eat you.");
    }

    @Override
    public void barkAt(Postman p) {
        System.out.println("I'm going to rip you apart.");
    }
}

在这种情况下,我们这样调用barkAt方法之一。

Dog cujo = new Rottweiler();
Person pat = new Postman();
cujo.barkAt(pat);

现在在这种特殊情况下,由编译器选择cujo.barkAt(pat);调用诸如public void barkAt(Person p)public void barkAt(Postman p)之类的方法。这些方法是彼此的重载。

为此,编译器查看传递给方法的表达式的类型-即变量pat。变量pat的类型为Person,因此编译器选择方法public void barkAt(Person p)

编译器要做的是选择是调用Rottweiler类还是Dog类中的方法。发生这种情况是在运行时,基于调用该方法的对象的 class ,而不是基于调用该方法的变量的 type

因此,在这种情况下,重要的是称为cujo的对象的类。在此示例中,cujoRottweiler,因此我们获得了该方法的替代版本-在Rottweiler类中定义的版本。

此示例将打印出I'm going to eat you

  

总结:

     
      
  • 根据参数 type 编译时选择重载
  •   
  • 根据对象 class 运行时选择替代
  •   

现在,可以使用强制转换来更改编译器对重载的选择。 不可能使用强制转换来更改覆盖的运行时选择。所以,我们可以写

cujo.barkAt((Postman) pat);

这一次,传递给方法的参数是类型Postman的表达式。编译器会相应地选择一个重载,这将显示I'm going to rip you apart.

答案 1 :(得分:-1)

  

投射会影响编译时重载方法的选择,但不会覆盖重载方法

重载的方法在编译时可见。但是被覆盖的方法在运行时变得可见。

拇指法则:

Java根据引用变量的内容而不是引用变量的类型来调用重写的方法。

下面的例子是自我解释。希望对您有所帮助。

class Animal {
    public void speak() {
        System.out.print("Animal sounds/roars.");
    }
}

class Human extends Animal {
    @Override                     // Method is overridden
    public void speak() {
        System.out.print("Humans talking english.");
    }

    public void speak(String words) {         // Method is overloaded.
        System.out.print("We have brain. We are intelligent."+words);
    }
}

class Earth {
    public static void main(String a[]) {
        Animal a = new Animal();
        a.speak(); // Prints Animal sounds/roars.

        Human h = new Human();
        h.speak();    // Prints "Humans talking english."

        Animal a = h; // Cast to superclass reference variable. However, underlying object is of Human.
        a.speak();    // Prints "Humans talking english." because speak() is known by Animal at compile time. During runtime, 
                      // the object contains the human object and hence java calls human overridden method.

        a.speak("I want to be human."); // Compile time error as speak(..) is not known by Animal at compile time.

    }
}