Java:多态只对具有相同签名的方法有用吗?

use*_*721 4 java parameters polymorphism factory

我看到的多态方法覆盖的唯一例子涉及不带参数的方法,或者至少具有相同的参数列表.考虑常见的Animal/Dog/Cat示例:

public abstract class Animal
{
    public abstract void makeSound();
}

public class Dog extends Animal
{
    public void makeSound()
    {
        System.out.println("woof");
    }
}

public class Cat extends Animal
{
    public void makeSound()
    {
        System.out.println("meow");
    }
}

public class ListenToAnimals
{
    public static void main(String[] args)
    {
        AnimalFactory factory = new AnimalFactory();
        Animal a = factory.getRandomAnimal(); // generate a dog or cat at random
        a.makeSound();
    }
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,一切都很好.现在让我们添加另一个在抽象类中部分实现的方法,同时在子类中获得更具体的行为:

public abstract class Animal
{   
    public abstract void makeSound();

    public void speak(String name)
    {
        System.out.println("My name is " + name);
    }
}

public class Dog extends Animal
{
    public void makeSound()
    {
        System.out.println("woof");
    }

    public void speak(String name)
    {
        super.speak(name);
        System.out.println("I'm a dog");
    }
}

public class Cat extends Animal
{
    public void makeSound()
    {
        System.out.println("meow");
    }

    public void speak(String name, int lives)
    {
        super.speak(name);
        System.out.println("I'm a cat and I have " + lives + " lives");
    }
}

public class ListenToAnimals
{
    public static void main(String[] args)
    {
        AnimalFactory factory = new AnimalFactory();
        Animal a = factory.getRandomAnimal(); // generate a dog or cat at random
        a.makeSound();
        // a.speak(NOW WHAT?
    }
}
Run Code Online (Sandbox Code Playgroud)

在主要方法的最后一个(注释)行中,我不知道该放什么,因为我不知道我有什么类型的动物.之前我没有必要担心,因为makeSound()没有接受任何参数.但是speak()确实如此,而且参数取决于Animal的类型.

我读过一些语言,比如Objective-C,允许变量参数列表,所以不应该出现这样的问题.有人知道在Java中实现这种事情的好方法吗?

Bri*_*128 6

您正在混淆方法重写和方法重载.在您的示例中,Cat该类有两种方法:

public void speak(String name) // It gets this from its super class
public void speak(String name, int lives)
Run Code Online (Sandbox Code Playgroud)

重载是一种定义具有类似功能但参数不同的方法的方法.如果你这样命名方法就没有区别了:

public void speakWithLives(String name, int lives)
Run Code Online (Sandbox Code Playgroud)

为避免混淆,java中的建议是@Override在尝试覆盖方法时使用注释.因此:

 // Compiles
@Override
public void speak(String name)

// Doesn't compile - no overriding occurs!
@Override
public void speak(String name, int lives)
Run Code Online (Sandbox Code Playgroud)

编辑:其他答案提到这一点,但我重复它的重点.添加新方法使得Cat该类不再能够Animal在所有情况下都被表示为,从而消除了多态性的优势.要使用新方法,您需要将其向下转换为Cat类型:

Animal mightBeACat = ...
if(mightBeACat instanceof Cat) {
  Cat definitelyACat = (Cat) mightBeACat;
  definitelyACat.speak("Whiskers", 9);
} else {
  // Definitely not a cat!
  mightBeACat.speak("Fred");
}
Run Code Online (Sandbox Code Playgroud)

我的IDE中的代码检查工具会在instanceof关键字上发出警告,指示可能的多态抽象失败.

  • +1 这是唯一涉及第二个示例中“Cat”类中的 talk 方法是“重载”而不是“重写”这一事实的答案。 (2认同)

Rei*_*ica 5

您的示例Cat不再是多态的,因为您必须知道它是Cat传递该参数的.即使Java允许它,你会如何使用它?