java 在java中,我们可以通过传递超类方法中使用的参数的子类来覆盖方法吗?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/31820828/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 19:10:56  来源:igfitidea点击:

In java, Can we override a method by passing subclass of the parameter used in super class method?

javaoverloadingoverriding

提问by SD Shaw

As per the rule, while overriding a method in subclass, parameters cannot be changed and have to be the same as in the super class. What if we pass subclass of parameter while overriding method ? Will it be called as overloading or overriding?

根据规则,在覆盖子类中的方法时,参数不能更改,并且必须与超类中的参数相同。如果我们在覆盖方法时传递参数的子类怎么办?它会被称为重载还是覆盖?

Based on my query I have written some code below.
I was expecting the output as "Dog eats Flesh Food" but to my surprise the output is "Animal eats Flesh Food" Will appreciate if someone can explain how does Animal method gets called when the object assigned is of type Dog ?

根据我的查询,我在下面编写了一些代码。
我期待输出为“狗吃肉食”,但令我惊讶的是输出是“动物吃肉食”,如果有人能解释当分配的对象为 Dog 类型时如何调用 Animal 方法,我会很感激吗?

    class Food {
        public String toString(){
            return "Normal Food";
        }
    }

    class Flesh extends Food {
        public String toString(){
            return "Flesh Food";
        }
    }

    class Animal {
        public void eat(Food food){
            System.out.println("Animal eats "+ food);
        }
    }

    class Dog extends Animal{

        public void eat(Flesh flesh){
            System.out.println("Dog eats "+ flesh);
        }
    }

    public class MyUtil {

        public static void main(String[] args) {

            Animal animal = new Dog(); 

            Flesh flesh = new Flesh();

            animal.eat(flesh);
        }
    }

回答by Paul Boddington

The method eatin Dogdoes not override the method eatin Animal. This is because the arguments are different (one requires Flesh, the other requires Food).

该方法eatDog不覆盖的方法eatAnimal。这是因为参数不同(一个需要Flesh,另一个需要Food)。

The eatmethods are overloads.

eat方法是重载。

Choosing between overloads takes place at compile time, not runtime. It is notbased on the actual class of the object on which the method is invoked, but the compile-time type (how the variable is declared).

重载之间的选择发生在编译时,而不是运行时。它不是基于调用该方法的对象的实际类,而是基于编译时类型(如何声明变量)。

animalhas compile-time type Animal. We know this because the declaration of the variable animalwas Animal animal = .... The fact that it is actually a Dogis irrelevant - it is the version of eatin Animalthat must be invoked.

animal具有编译时类型Animal。我们知道这一点是因为变量的声明animalAnimal animal = .... 它实际上是 a 的事实Dog无关紧要 -必须调用eatin的版本Animal

On the other hand, the toStringmethod in Fleshdoesoverride the toStringmethod in Food.

另一方面,toStringinFleshtoString方法确实覆盖了 中的方法Food

When one method overrides another it is the actual class of the object that the method is invoked on that determines which version runs.

当一个方法覆盖另一个方法时,调用该方法的对象的实际类决定了运行哪个版本。

In the eatmethod of Animal, even though the argument has compile-time type Food, if you pass an instance of Fleshto it, it is the toStringmethod in Fleshthat will execute.

在 的eat方法中Animal,即使参数具有编译时类型Food,如果您将 的实例传递Flesh给它,它将执行其中的toString方法Flesh

Therefore you get the message "Animal eats Flesh Food".

因此,您会收到消息"Animal eats Flesh Food"

回答by Ahmad Al-Kurdi

No, we can not in this case you can check it by adding @Override above the eat method in Dog class so compilation error will appear like this :

不,我们不能在这种情况下您可以通过在 Dog 类中的eat 方法上方添加@Override 来检查它,因此编译错误将如下所示:

@Override
public void eat(Flesh flesh){
   System.out.println("Dog eats "+ flesh);
}

Make sure that in override the parameters should be as parent class in type and order.

确保在覆盖中,参数的类型和顺序应与父类相同。

回答by dave

You can use the @overrideannotation to inform the compiler that you are trying to override a method within the superclass.

您可以使用@override注释通知编译器您正在尝试覆盖超类中的方法。

e.g.

例如

 class Dog extends Animal{

    @Override
    public void eat(Flesh flesh){
        System.out.println("Dog eats "+ flesh);
    }
 }

In your code, now the compiler will generate an error, because this method does not override eat, you need to have the same parameter type.

在你的代码中,现在编译器会产生一个错误,因为这个方法没有覆盖eat,你需要有相同的参数类型。

However, changing the Fleshparameter to Foodtype will resolve the problem:

但是,将Flesh参数更改为Foodtype 将解决问题:

class Dog extends Animal{

    @Override
    public void eat(Food food){
        System.out.println("Dog eats "+ food);
    }
}

Now you can do the following:

现在您可以执行以下操作:

public class MyUtil {

    public static void main(String[] args) {

        Animal animal = new Dog(); 

        Food food = new Flesh();

        animal.eat(food);
    }
}

回答by Hyman Bu

When you do this: Animal animal = new Dog();it's upcasting.

当你这样做时: Animal animal = new Dog();它是向上的。

And you do not override the method

并且您不会覆盖该方法

public void eat(Flesh flesh){
    System.out.println("Dog eats "+ flesh);
}

so it calls the method eat(Food food)of Animal

所以它调用该方法eat(Food food)Animal

回答by Deepa

In java, Can we override a method by passing subclass of the parameter used in super class method?

在java中,我们可以通过传递超类方法中使用的参数的子类来覆盖方法吗?

NO.

不。

Explanation with example :

举例说明:

Assume we can override a method by passing subclass of the parameter used in super class method.

假设我们可以通过传递超类方法中使用的参数的子类来覆盖方法。

class A {
    public void print(Oject obj) 
    {
      System.out.println(obj.toString());
     }
}

class B extends A {
    @Override
     public void print(String str) 
     {
        System.out.println(str.toString());
     }
}

class C extends A {
   @Override
   public void print(Integer in) {
      System.out.println(in.toString());
   }
}

class MainTest {
   public static void main(String args[]) 
   {
      Integer in = new Integer(3);
      A a = new B(); // developer by mistake types new B() instead of new C()
      a.print(in);  // compiler will allow this because class A has print method which can take any subclass of Object type(in this case any class because Object is superclass of all classes in java).
    }
}

But think what happens during runtime ?

但是想想在运行时会发生什么?

During runtime, method is called on the actual object to which reference is pointing to. In our case it is pointing to class B. So JVM will look into class B for method execution and it would be a great shock to JVM because class B does not have a overriden method with signature public void print(Integer in) and it will fail at runtime.

在运行时,对引用指向的实际对象调用方法。在我们的例子中,它指向 B 类。所以 JVM 将查看 B 类的方法执行,这对 JVM 来说将是一个巨大的冲击,因为 B 类没有带有签名 public void print(Integer in) 的重写方法,它会运行时失败。

The consequence of this is application will crash at runtime rather than compile time.

这样做的结果是应用程序将在运行时而不是编译时崩溃。

Overriding rules in Java :

Java 中的覆盖规则:

  • Arguments must be the same & return types must be compatible
  • The method can't be less accessible
  • 参数必须相同且返回类型必须兼容
  • 方法不能少

=============================

==============================

In your example what happens is :

在你的例子中会发生什么:

During compile time: compiler makes sure that eat method can be called on reference type(which is Aniaml class). Since Animal class has a method public void eat(Food food) which can take any Food type and subclass of Food type as input parameter(polymorphism), compilation passes.

在编译期间:编译器确保可以在引用类型(即 Aniaml 类)上调用 eat 方法。由于 Animal 类有一个方法 public void eat(Food food) 可以将任何 Food 类型和 Food 类型的子类作为输入参数(多态性),编译通过。

In general, compiler guarantees that particular method is callable for a specific reference type.

通常,编译器保证特定方法对于特定引用类型是可调用的。

During run time :Actual method called is, most specific version of the method for that object type(Dog class).Since JVM is not able to find the overriden method i.e with the same method name and same argument type declared in sub class (Dog class), it checks its superclass(Animal class) and finds the method and executes.

在运行时:调用的实际方法是该对象类型(Dog 类)的方法的最具体版本。因为 JVM 无法找到覆盖方法,即在子类(Dog)中声明具有相同方法名称和相同参数类型的方法类),它检查其超类(动物类)并找到方法并执行。

public void eat(Food food)and public void eat(Flesh flesh)are not same from the perspective of overriding methods.

从覆盖方法的角度来看,public voideat(Food food)public voideat(Flesh果肉)是不一样的。

In general, when you call a method on an object reference, you're calling the most specific version of the method for that object type during runtime. But if it doesn't find one it will go up the hierarchy.Worst case Super class will definitely have the method implementation otherwise compilation wont pass.

通常,当您在对象引用上调用方法时,您是在运行时为该对象类型调用该方法的最具体版本。但是如果它没有找到,它就会上升到层次结构。最坏的情况是超类肯定会有方法实现,否则编译不会通过。