在Java中,当有人问:

什么是多态性?

重载或重写是可以接受的答案吗?

我认为事情远不止如此。

如果你有一个抽象基类,它定义了一个没有实现的方法,并且你在子类中定义了这个方法,这仍然是覆盖的吗?

我认为超负荷肯定不是正确的答案。


当前回答

表达多态性最清晰的方法是通过抽象基类(或接口)

public abstract class Human{
   ...
   public abstract void goPee();
}

这个类是抽象的,因为goPee()方法对人类是不可定义的。它只对子类Male和Female可定义。此外,人是一个抽象的概念——你不能创造一个既不是男性也不是女性的人。一定是两者之一。

因此,我们通过使用抽象类来延迟实现。

public class Male extends Human{
...
    @Override
    public void goPee(){
        System.out.println("Stand Up");
    }
}

and

public class Female extends Human{
...
    @Override
    public void goPee(){
        System.out.println("Sit Down");
    }
}

现在我们可以让一屋子的人去尿尿了。

public static void main(String[] args){
    ArrayList<Human> group = new ArrayList<Human>();
    group.add(new Male());
    group.add(new Female());
    // ... add more...

    // tell the class to take a pee break
    for (Human person : group) person.goPee();
}

运行该命令会得到:

Stand Up
Sit Down
...

其他回答

多态性涉及到一种语言通过使用单一接口统一处理不同对象的能力;因此,它与覆盖有关,因此接口(或基类)是多态的,实现者是覆盖的对象(同一奖章的两个面)

无论如何,这两个术语之间的区别可以用其他语言更好地解释,比如c++:如果基本函数是虚的,那么c++中的多态对象的行为就像Java对应的对象一样,但如果方法不是虚的,那么代码跳转是静态解析的,并且在运行时不检查真实类型,因此,多态包括对象根据用于访问它的接口而表现不同的能力;让我在伪代码中做一个例子:

class animal {
    public void makeRumor(){
        print("thump");
    }
}
class dog extends animal {
    public void makeRumor(){
        print("woff");
    }
}

animal a = new dog();
dog b = new dog();

a.makeRumor() -> prints thump
b.makeRumor() -> prints woff

(假设makeRumor不是虚拟的)

Java并没有真正提供这种级别的多态性(也称为对象切片)。

动物a =新狗(); Dog b = new Dog ();

a.makeRumor() -> prints thump
b.makeRumor() -> prints woff

在这两种情况下,它只会打印woff.. 因为a和b指的是类dog

没有:

重载是指使用相同的函数名,但接受不同的参数。

重写是指子类用自己的方法替换父类的方法(这本身不构成多态性)。

多态性是后期绑定,例如,基类(父类)方法被调用,但直到运行时应用程序才知道实际对象是什么——它可能是一个方法不同的子类。这是因为任何子类都可以在定义基类的地方使用。

在Java中,你可以在集合库中看到很多多态性:

int countStuff(List stuff) {
  return stuff.size();
}

List是基类,编译器不知道你计数的是链表、向量、数组还是自定义列表实现,只要它像List一样:

List myStuff = new MyTotallyAwesomeList();
int result = countStuff(myStuff);

如果你超载了,你会:

int countStuff(LinkedList stuff) {...}
int countStuff(ArrayList stuff) {...}
int countStuff(MyTotallyAwesomeList stuff) {...}
etc...

编译器会选择countStuff()的正确版本来匹配参数。

重写和重载都用于实现多态性。

你可以在一个类中有一个方法 它在或中被覆盖 更多的子类。这个方法可以 不同的东西取决于哪个 类用于实例化对象。

    abstract class Beverage {
       boolean isAcceptableTemperature();
    }

    class Coffee extends Beverage {
       boolean isAcceptableTemperature() { 
           return temperature > 70;
       }
    }

    class Wine extends Beverage {
       boolean isAcceptableTemperature() { 
           return temperature < 10;
       }
    }

你也可以有一种方法 用两组或多组参数重载。这个方法可以 不同的东西基于 传递的参数类型。

    class Server {
        public void pour (Coffee liquid) {
            new Cup().fillToTopWith(liquid);
        }

        public void pour (Wine liquid) {
            new WineGlass().fillHalfwayWith(liquid);
        }

        public void pour (Lemonade liquid, boolean ice) {
            Glass glass = new Glass();
            if (ice) {
                glass.fillToTopWith(new Ice());
            }
            glass.fillToTopWith(liquid);
        }
    }

下面是伪c# /Java中的多态性示例:

class Animal
{
    abstract string MakeNoise ();
}

class Cat : Animal {
    string MakeNoise () {
        return "Meow";
    }
}

class Dog : Animal {
    string MakeNoise () {
        return "Bark";
    }
}

Main () {
   Animal animal = Zoo.GetAnimal ();
   Console.WriteLine (animal.MakeNoise ());
}

Main函数不知道动物的类型,并且依赖于MakeNoise()方法的特定实现的行为。

编辑:看来布莱恩先我一步了。有趣的是我们用了同样的例子。但是上面的代码应该有助于阐明概念。

表达多态性最清晰的方法是通过抽象基类(或接口)

public abstract class Human{
   ...
   public abstract void goPee();
}

这个类是抽象的,因为goPee()方法对人类是不可定义的。它只对子类Male和Female可定义。此外,人是一个抽象的概念——你不能创造一个既不是男性也不是女性的人。一定是两者之一。

因此,我们通过使用抽象类来延迟实现。

public class Male extends Human{
...
    @Override
    public void goPee(){
        System.out.println("Stand Up");
    }
}

and

public class Female extends Human{
...
    @Override
    public void goPee(){
        System.out.println("Sit Down");
    }
}

现在我们可以让一屋子的人去尿尿了。

public static void main(String[] args){
    ArrayList<Human> group = new ArrayList<Human>();
    group.add(new Male());
    group.add(new Female());
    // ... add more...

    // tell the class to take a pee break
    for (Human person : group) person.goPee();
}

运行该命令会得到:

Stand Up
Sit Down
...