繁体   English   中英

覆盖和重载方法

[英]Overridden and Overloaded Methods

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

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

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

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

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

那行指的是

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

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

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类中的方法。 这是在运行时发生的,它取决于调用该方法的对象的 ,而不是基于调用该方法的变量的类型

因此,在这种情况下,重要的是称为cujo的对象的类。 而在这个例子中, cujoRottweiler ,所以我们得到了该方法的重写版本-在定义的Rottweiler类。

这个例子会打印出来I'm going to eat you

总结一下:

  • 重载是在编译时根据参数类型选择的
  • 覆盖是在运行时根据对象类选择的

现在,可以使用强制转换来更改编译器对重载的选择。 这是不可能用铸造改变运行时间选择替代的。 所以,我们可以写

cujo.barkAt((Postman) pat);

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

强制转换会影响编译时重载方法的选择,但不会影响重载方法的选择

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

经验法则:

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.

    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM