简体   繁体   English

覆盖和重载方法

[英]Overridden and Overloaded Methods

What does it mean by "Casting affects the selection of overloaded methods at compile time but not overridden methods"? “强制转换会影响编译时重载方法的选择,但不会覆盖重载方法”是什么意思?

I read the following passage on "Overridden methods and dynamic binding" ( https://www.oreilly.com/library/view/learning-java-4th/9781449372477/ch06s01.html ) and I couldn't understand the last paragraph 我阅读了以下有关“重写的方法和动态绑定”的文章( https://www.oreilly.com/library/view/learning-java-4th/9781449372477/ch06s01.html ),但我听不懂最后一段

"In a previous section, we mentioned that overloaded methods are selected by the compiler at compile time. Overridden methods, on the other hand, are selected dynamically at runtime. Even if we create an instance of a subclass our code has never seen before (perhaps a new class loaded over the network), any overriding methods that it contains are located and used at runtime, replacing those that existed when we last compiled our code. “在上一节中,我们提到了重载方法是由编译器在编译时选择的。另一方面,被覆盖的方法是在运行时动态选择的。即使我们创建了一个子类的实例,我们的代码也从未见过(可能是一个通过网络加载的新类),它包含的所有覆盖方法都可以在运行时找到并使用,以替换上次编译代码时存在的方法。

In contrast, if we created a new class that implements an additional, more specific, overloaded method, and replace the compiled class in our classpath with it, our code would continue to use the implementation it discovered originally. 相反,如果我们创建一个新的类来实现一个额外的,更具体的,重载的方法,并用它替换我们的类路径中的已编译类,则我们的代码将继续使用其最初发现的实现。 This situation would persist until we recompiled our code along with the new class. 这种情况将一直持续到我们将代码与新类一起重新编译。 Another effect of this is that casting (ie, explicitly telling the compiler to treat an object as one of its assignable types) affects the selection of overloaded methods at compile time but not overridden methods." 这样做的另一个效果是,强制转换(即,明确地告诉编译器将对象视为其可分配类型之一)在编译时会影响对重载方法的选择,但不会影响重写的方法。”

I couldnt understand the "Casting" line: "Another effect of this is that casting (ie, explicitly telling the compiler to treat an object as one of its assignable types) affects the selection of overloaded methods at compile time but not overridden methods." 我无法理解“铸造”这一行:“这的另一个影响是,强制转换(即,明确地告诉编译器将对象视为其可分配类型之一)在编译时会影响重载方法的选择,但不会影响重载方法的选择。”

That line is referring to the fact that 那行指的是

  • overloaded versions of a method are chosen at compile time, based on the compile-time types of the arguments that you are passing; 方法的重载版本是在编译时根据传递的参数的编译时类型选择的; whereas
  • overridden methods are chosen at run time, based on the classes of the objects on which you call each method. 根据调用每个方法的对象的类,在运行时选择覆盖的方法。

To understand this distinction, consider a situation where you have both overrides and overloads, like this. 要理解这种区别,请考虑这样的情况,即同时具有覆盖和重载。

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.");
    }
}

In this situation, we call one of these barkAt methods, like this. 在这种情况下,我们像这样调用这些barkAt方法之一。

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

Now in this particular case, it's the compiler that chooses whether cujo.barkAt(pat); 现在在这种情况下,是由编译器选择cujo.barkAt(pat); calls a method like public void barkAt(Person p) or public void barkAt(Postman p) . 调用诸如public void barkAt(Person p)public void barkAt(Postman p) These methods are overloads of one another. 这些方法是彼此的重载。

To do this, the compiler looks at the type of the expression being passed to the method - that is, the variable pat . 为此,编译器查看传递给该方法的表达式的类型-即变量pat The variable pat is of type Person , so the compiler chooses the method public void barkAt(Person p) . 变量pat的类型为Person ,因此编译器选择方法public void barkAt(Person p)

What the compiler doesn't do is choose whether it's the method from the Rottweiler class or the Dog class that gets called. 编译器不会选择要调用的是Rottweiler类还是Dog类中的方法。 That happens at run time, based on the class of the object on which the method gets called, NOT on the type of the variable that you call the method on. 这是在运行时发生的,它取决于调用该方法的对象的 ,而不是基于调用该方法的变量的类型

So in this case, what matters is the class of the object called cujo . 因此,在这种情况下,重要的是称为cujo的对象的类。 And in this example, cujo is a Rottweiler , so we get the overridden version of the method - the one defined in the Rottweiler class. 而在这个例子中, cujoRottweiler ,所以我们得到了该方法的重写版本-在定义的Rottweiler类。

This example will print out I'm going to eat you . 这个例子会打印出来I'm going to eat you

To summarise: 总结一下:

  • The overload is chosen at compile time based on the parameter type . 重载是在编译时根据参数类型选择的
  • The override is chosen at run time based on the object class . 覆盖是在运行时根据对象类选择的

Now, it's possible to use casting to change the compiler's choice of overload. 现在,可以使用强制转换来更改编译器对重载的选择。 It's not possible to use casting to change the run time choice of override. 这是不可能用铸造改变运行时间选择替代的。 So, we could write 所以,我们可以写

cujo.barkAt((Postman) pat);

This time, the parameter passed to the method is an expression of type Postman . 这次,传递给该方法的参数是Postman类型的表达式。 The compiler chooses an overload accordingly, and this will print I'm going to rip you apart. 编译器会相应地选择一个重载,这将打印出来, I'm going to rip you apart. .

Casting affects the selection of overloaded methods at compile time but not overridden methods 强制转换会影响编译时重载方法的选择,但不会影响重载方法的选择

Overloaded methods are visible at compile time. 重载的方法在编译时可见。 But overridden methods becomes visible at runtime. 但是,被覆盖的方法在运行时变得可见。

Thumb Rule: 经验法则:

Java calls the overridden methods based on contents of reference variable and not type of reference variables. Java根据引用变量的内容而不是引用变量的类型来调用重写的方法。

Below example is self explainatory. 下面的例子是自我解释。 Hope it helps. 希望能帮助到你。

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