371

在 Java 方面,当有人问:

什么是多态性?

重载覆盖是一个可以接受的答案吗?

我认为还有更多的东西。

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

我认为重载肯定不是正确的答案。

4

21 回答 21

933

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

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

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
...
于 2008-09-30T20:33:51.040 回答
99

多态性是类实例表现得好像它是其继承树中另一个类的实例的能力,通常是它的祖先类之一。例如,在 Java 中,所有类都继承自 Object。因此,您可以创建一个 Object 类型的变量并将任何类的实例分配给它。

覆盖_是一种发生在从另一个类继承的类中的函数。覆盖函数“替换”从基类继承的函数,但这样做的方式是,即使其类的实例通过多态性伪装成不同的类型,也会调用它。参考前面的示例,您可以定义自己的类并覆盖 toString() 函数。因为这个函数是从 Object 继承的,所以如果你把这个类的一个实例复制到一个 Object 类型的变量中,它仍然可以使用。通常,如果您在类伪装成 Object 时调用 toString(),则实际触发的 toString 版本是在 Object 本身上定义的版本。但是,由于该函数是一个覆盖,因此即使在类实例'

重载是定义多个具有相同名称但具有不同参数的方法的操作。它与覆盖或多态无关。

于 2008-09-30T19:51:18.303 回答
57

多态是指不止一种形式,同一个对象根据需要执行不同的操作。

多态性可以通过两种方式来实现,它们是

  1. 方法覆盖
  2. 方法重载

方法重载是指使用相同的方法名在同一个类中编写两个或多个方法,但传递的参数不同。

方法覆盖意味着我们在不同的类中使用方法名称,这意味着在子类中使用父类方法。

在Java中实现多态一个超类引用变量可以持有子类对象。

为了实现多态性,每个开发人员都必须在项目中使用相同的方法名称。

于 2012-10-21T05:07:45.327 回答
45

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

您可以在一个类中拥有一个在一个或多个子类中被覆盖的方法。该方法根据用于实例化对象的类执行不同的操作。

    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);
        }
    }
于 2008-09-30T19:42:37.950 回答
41

这是伪 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() 方法的特定实现行为。

编辑:看起来布莱恩打败了我。有趣的是,我们使用了相同的示例。但是上面的代码应该有助于澄清概念。

于 2008-09-30T19:41:50.993 回答
15

你是对的,重载不是答案。

两者都不是压倒一切的。覆盖是获得多态性的方法。多态性是对象根据其类型改变行为的能力。当表现出多态性的对象的调用者不知道该对象是什么特定类型时,这一点得到了最好的证明。

于 2008-09-30T19:35:05.003 回答
11

具体来说,重载或覆盖并不能给出完整的画面。多态性只是对象根据其类型专门化其行为的能力。

我不同意这里的一些答案,因为重载是多态性(参数多态性)的一种形式,在这种情况下,具有相同名称的方法可以表现不同,给出不同的参数类型。一个很好的例子是运算符重载。您可以定义“+”来接受不同类型的参数——比如字符串或整数——并且基于这些类型,“+”的行为会有所不同。

多态性还包括继承和覆盖方法,尽管它们在基类型中可以是抽象的或虚拟的。在基于继承的多态性方面,Java 仅支持单类继承,将其多态行为限制为单基类型链。Java 确实支持多个接口的实现,这是另一种形式的多态行为。

于 2008-09-30T19:51:19.863 回答
7

多态性只是意味着“多种形式”。

它不需要继承来实现......作为接口实现,它根本不是继承,服务于多态需求。可以说,接口实现比继承“更好”地服务于多态需求。

例如,你会创建一个超类来描述所有可以飞行的东西吗?我应该不这么认为。您最好创建一个描述飞行的界面并将其保留在那里。

因此,由于接口描述行为,而方法名称描述行为(对程序员而言),将方法重载视为一种较小形式的多态性并不过分。

于 2010-12-20T05:02:32.547 回答
6

经典的例子,狗和猫都是动物,动物有方法makeNoise。我可以遍历一组对它们调用 makeNoise 的动物,并期望它们会在那里执行相应的实现。

调用代码不必知道它们是什么特定的动物。

这就是我认为的多态性。

于 2008-09-30T19:37:58.210 回答
5

虽然,多态性已经在这篇文章中进行了详细的解释,但我想更加强调为什么是它的一部分。

为什么多态在任何 OOP 语言中都如此重要。

让我们尝试为有和没有继承/多态的电视构建一个简单的应用程序。发布应用程序的每个版本,我们都会进行一次小型回顾。

假设您是一家电视公司的软件工程师,您被要求为音量、亮度和颜色控制器编写软件,以根据用户命令增加和减少它们的值。

您首先为这些功能中的每一个编写类,方法是添加

  1. 设置:- 设置控制器的值。(假设这有控制器特定的代码)
  2. 获取:- 获取控制器的值。(假设这有控制器特定的代码)
  3. 调整:-验证输入并设置控制器。(通用验证..独立于控制器)
  4. 与控制器的用户输入映射:- 获取用户输入并相应地调用控制器。

应用程序版本 1

import java.util.Scanner;    
class VolumeControllerV1 {
    private int value;
    int get()    {
        return value;
    }
    void set(int value) {
        System.out.println("Old value of VolumeController \t"+this.value);
        this.value = value;
        System.out.println("New value of VolumeController \t"+this.value);
    }
    void adjust(int value)  {
        int temp = this.get();
        if(((value > 0) && (temp >= 100)) || ((value < 0) && (temp <= 0)))    {
            System.out.println("Can not adjust any further");
            return;
        }
        this.set(temp + value);
    }
}
class  BrightnessControllerV1 {
    private int value;
    int get()    {
        return value;
    }
    void set(int value) {
        System.out.println("Old value of BrightnessController \t"+this.value);
        this.value = value;
        System.out.println("New value of BrightnessController \t"+this.value);
    }
    void adjust(int value)  {
        int temp = this.get();
        if(((value > 0) && (temp >= 100)) || ((value < 0) && (temp <= 0)))    {
            System.out.println("Can not adjust any further");
            return;
        }
        this.set(temp + value);
    }
}
class ColourControllerV1    {
    private int value;
    int get()    {
        return value;
    }
    void set(int value) {
        System.out.println("Old value of ColourController \t"+this.value);
        this.value = value;
        System.out.println("New value of ColourController \t"+this.value);
    }
    void adjust(int value)  {
        int temp = this.get();
        if(((value > 0) && (temp >= 100)) || ((value < 0) && (temp <= 0)))    {
            System.out.println("Can not adjust any further");
            return;
        }
        this.set(temp + value);
    }
}

/*
 *       There can be n number of controllers
 * */
public class TvApplicationV1 {
    public static void main(String[] args)  {
        VolumeControllerV1 volumeControllerV1 = new VolumeControllerV1();
        BrightnessControllerV1 brightnessControllerV1 = new BrightnessControllerV1();
        ColourControllerV1 colourControllerV1 = new ColourControllerV1();


        OUTER: while(true) {
            Scanner sc=new Scanner(System.in);
            System.out.println(" Enter your option \n Press 1 to increase volume \n Press 2 to decrease volume");
            System.out.println(" Press 3 to increase brightness \n Press 4 to decrease brightness");
            System.out.println(" Press 5 to increase color \n Press 6 to decrease color");
            System.out.println("Press any other Button to shutdown");
            int button = sc.nextInt();
            switch (button) {
                case  1:    {
                    volumeControllerV1.adjust(5);
                    break;
                }
                case 2: {
                    volumeControllerV1.adjust(-5);
                    break;
                }
                case  3:    {
                    brightnessControllerV1.adjust(5);
                    break;
                }
                case 4: {
                    brightnessControllerV1.adjust(-5);
                    break;
                }
                case  5:    {
                    colourControllerV1.adjust(5);
                    break;
                }
                case 6: {
                colourControllerV1.adjust(-5);
                break;
            }
            default:
                System.out.println("Shutting down...........");
                break OUTER;
        }

    }
    }
}

现在您已经准备好部署我们的第一个工作应用程序版本。是时候分析到目前为止所做的工作了。

TV 应用程序版本 1 中的问题

  1. Adjust(int value) 代码在所有三个类中都是重复的。您希望最小化代码重复性。(但您没有想到通用代码并将其移至某个超类以避免重复代码)

只要您的应用程序按预期工作,您就决定接受它。

有时,你的老板会回来找你,要求你为现有的应用程序添加重置功能。重置会将所有 3 个三个控制器设置为其各自的默认值。

您开始为新功能编写一个新类 (ResetFunctionV2),并为这个新功能映射用户输入映射代码。

应用程序版本 2

import java.util.Scanner;
class VolumeControllerV2    {

    private int defaultValue = 25;
    private int value;

    int getDefaultValue() {
        return defaultValue;
    }
    int get()    {
        return value;
    }
    void set(int value) {
        System.out.println("Old value of VolumeController \t"+this.value);
        this.value = value;
        System.out.println("New value of VolumeController \t"+this.value);
    }
    void adjust(int value)  {
        int temp = this.get();
        if(((value > 0) && (temp >= 100)) || ((value < 0) && (temp <= 0)))    {
            System.out.println("Can not adjust any further");
            return;
        }
        this.set(temp + value);
    }
}
class  BrightnessControllerV2   {

    private int defaultValue = 50;
    private int value;
    int get()    {
        return value;
    }
    int getDefaultValue() {
        return defaultValue;
    }
    void set(int value) {
        System.out.println("Old value of BrightnessController \t"+this.value);
        this.value = value;
        System.out.println("New value of BrightnessController \t"+this.value);
    }
    void adjust(int value)  {
        int temp = this.get();
        if(((value > 0) && (temp >= 100)) || ((value < 0) && (temp <= 0)))    {
            System.out.println("Can not adjust any further");
            return;
        }
        this.set(temp + value);
    }
}
class ColourControllerV2    {

    private int defaultValue = 40;
    private int value;
    int get()    {
        return value;
    }
    int getDefaultValue() {
        return defaultValue;
    }
    void set(int value) {
        System.out.println("Old value of ColourController \t"+this.value);
        this.value = value;
        System.out.println("New value of ColourController \t"+this.value);
    }
    void adjust(int value)  {
        int temp = this.get();
        if(((value > 0) && (temp >= 100)) || ((value < 0) && (temp <= 0)))    {
            System.out.println("Can not adjust any further");
            return;
        }
        this.set(temp + value);
    }
}

class ResetFunctionV2 {

    private VolumeControllerV2 volumeControllerV2 ;
    private BrightnessControllerV2 brightnessControllerV2;
    private ColourControllerV2 colourControllerV2;

    ResetFunctionV2(VolumeControllerV2 volumeControllerV2, BrightnessControllerV2 brightnessControllerV2, ColourControllerV2 colourControllerV2)  {
        this.volumeControllerV2 = volumeControllerV2;
        this.brightnessControllerV2 = brightnessControllerV2;
        this.colourControllerV2 = colourControllerV2;
    }
    void onReset()    {
        volumeControllerV2.set(volumeControllerV2.getDefaultValue());
        brightnessControllerV2.set(brightnessControllerV2.getDefaultValue());
        colourControllerV2.set(colourControllerV2.getDefaultValue());
    }
}
/*
 *       so on
 *       There can be n number of controllers
 *
 * */
public class TvApplicationV2 {
    public static void main(String[] args)  {
        VolumeControllerV2 volumeControllerV2 = new VolumeControllerV2();
        BrightnessControllerV2 brightnessControllerV2 = new BrightnessControllerV2();
        ColourControllerV2 colourControllerV2 = new ColourControllerV2();

        ResetFunctionV2 resetFunctionV2 = new ResetFunctionV2(volumeControllerV2, brightnessControllerV2, colourControllerV2);

        OUTER: while(true) {
            Scanner sc=new Scanner(System.in);
            System.out.println(" Enter your option \n Press 1 to increase volume \n Press 2 to decrease volume");
            System.out.println(" Press 3 to increase brightness \n Press 4 to decrease brightness");
            System.out.println(" Press 5 to increase color \n Press 6 to decrease color");
            System.out.println(" Press 7 to reset TV \n Press any other Button to shutdown");
            int button = sc.nextInt();
            switch (button) {
                case  1:    {
                    volumeControllerV2.adjust(5);
                    break;
                }
                case 2: {
                    volumeControllerV2.adjust(-5);
                    break;
                }
                case  3:    {
                    brightnessControllerV2.adjust(5);
                    break;
                }
                case 4: {
                    brightnessControllerV2.adjust(-5);
                    break;
                }
                case  5:    {
                    colourControllerV2.adjust(5);
                    break;
                }
                case 6: {
                    colourControllerV2.adjust(-5);
                    break;
                }
                case 7: {
                    resetFunctionV2.onReset();
                    break;
                }
                default:
                    System.out.println("Shutting down...........");
                    break OUTER;
            }

        }
    }
}

因此,您的应用程序已准备好使用重置功能。但是,现在你开始意识到

TV 应用程序版本 2 中的问题

  1. 如果产品中引入了新控制器,则必须更改重置功能代码。
  2. 如果控制器的计数增长得非常高,那么您在持有控制器的引用时就会遇到问题。
  3. 重置功能代码与所有控制器类的代码紧密耦合(获取和设置默认值)。
  4. 重置要素类(ResetFunctionV2)可以访问控制器类(调整)的其他方法,这是不可取的。

同时,您听到老板说您可能需要添加一项功能,其中每个控制器在启动时需要通过互联网从公司托管的驱动程序库中检查最新版本的驱动程序。

现在您开始认为要添加的这个新功能类似于重置功能,如果您不重构应用程序,应用程序问题 (V2) 将成倍增加。

您开始考虑使用继承,以便可以利用 JAVA 的多态能力,并添加一个新的抽象类(ControllerV3)到

  1. 声明 get 和 set 方法的签名。
  2. 包含之前在所有控制器之间复制的调整方法实现。
  3. 声明 setDefault 方法,以便可以利用多态轻松实现重置功能。

通过这些改进,您可以准备好 TV 应用程序的第 3 版。

应用程序版本 3

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

abstract class ControllerV3 {
    abstract void set(int value);
    abstract int get();
    void adjust(int value)  {
        int temp = this.get();
        if(((value > 0) && (temp >= 100)) || ((value < 0) && (temp <= 0)))    {
            System.out.println("Can not adjust any further");
            return;
        }
        this.set(temp + value);
    }
    abstract void setDefault();
}
class VolumeControllerV3 extends ControllerV3   {

    private int defaultValue = 25;
    private int value;

    public void setDefault() {
        set(defaultValue);
    }
    int get()    {
        return value;
    }
    void set(int value) {
        System.out.println("Old value of VolumeController \t"+this.value);
        this.value = value;
        System.out.println("New value of VolumeController \t"+this.value);
    }
}
class  BrightnessControllerV3  extends ControllerV3   {

    private int defaultValue = 50;
    private int value;

    public void setDefault() {
        set(defaultValue);
    }
    int get()    {
        return value;
    }
    void set(int value) {
        System.out.println("Old value of BrightnessController \t"+this.value);
        this.value = value;
        System.out.println("New value of BrightnessController \t"+this.value);
    }
}
class ColourControllerV3 extends ControllerV3   {

    private int defaultValue = 40;
    private int value;

    public void setDefault() {
        set(defaultValue);
    }
    int get()    {
        return value;
    }
    void set(int value) {
        System.out.println("Old value of ColourController \t"+this.value);
        this.value = value;
        System.out.println("New value of ColourController \t"+this.value);
    }
}

class ResetFunctionV3 {

    private List<ControllerV3> controllers = null;

    ResetFunctionV3(List<ControllerV3> controllers)  {
        this.controllers = controllers;
    }
    void onReset()    {
        for (ControllerV3 controllerV3 :this.controllers)  {
            controllerV3.setDefault();
        }
    }
}
/*
 *       so on
 *       There can be n number of controllers
 *
 * */
public class TvApplicationV3 {
    public static void main(String[] args)  {
        VolumeControllerV3 volumeControllerV3 = new VolumeControllerV3();
        BrightnessControllerV3 brightnessControllerV3 = new BrightnessControllerV3();
        ColourControllerV3 colourControllerV3 = new ColourControllerV3();

        List<ControllerV3> controllerV3s = new ArrayList<>();
        controllerV3s.add(volumeControllerV3);
        controllerV3s.add(brightnessControllerV3);
        controllerV3s.add(colourControllerV3);

        ResetFunctionV3 resetFunctionV3 = new ResetFunctionV3(controllerV3s);

        OUTER: while(true) {
            Scanner sc=new Scanner(System.in);
            System.out.println(" Enter your option \n Press 1 to increase volume \n Press 2 to decrease volume");
            System.out.println(" Press 3 to increase brightness \n Press 4 to decrease brightness");
            System.out.println(" Press 5 to increase color \n Press 6 to decrease color");
            System.out.println(" Press 7 to reset TV \n Press any other Button to shutdown");
            int button = sc.nextInt();
            switch (button) {
                case  1:    {
                    volumeControllerV3.adjust(5);
                    break;
                }
                case 2: {
                    volumeControllerV3.adjust(-5);
                    break;
                }
                case  3:    {
                    brightnessControllerV3.adjust(5);
                    break;
                }
                case 4: {
                    brightnessControllerV3.adjust(-5);
                    break;
                }
                case  5:    {
                    colourControllerV3.adjust(5);
                    break;
                }
                case 6: {
                    colourControllerV3.adjust(-5);
                    break;
                }
                case 7: {
                    resetFunctionV3.onReset();
                    break;
                }
                default:
                    System.out.println("Shutting down...........");
                    break OUTER;
            }

        }
    }
}

尽管 V2 的问题列表中列出的大部分问题都得到了解决,除了

TV 应用程序版本 3 中的问题

  1. 重置要素类(ResetFunctionV3)可以访问控制器类(调整)的其他方法,这是不可取的。

同样,您考虑解决这个问题,因为现在您还有另一个功能(启动时更新驱动程序)要实现。如果您不修复它,它也会被复制到新功能中。

因此,您划分抽象类中定义的合同并为

  1. 重置功能。
  2. 驱动程序更新。

并让您的第一个具体课程如下实现它们

应用程序版本 4

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

interface OnReset {
    void setDefault();
}
interface OnStart {
    void checkForDriverUpdate();
}
abstract class ControllerV4 implements OnReset,OnStart {
    abstract void set(int value);
    abstract int get();
    void adjust(int value)  {
        int temp = this.get();
        if(((value > 0) && (temp >= 100)) || ((value < 0) && (temp <= 0)))    {
            System.out.println("Can not adjust any further");
            return;
        }
        this.set(temp + value);
    }
}

class VolumeControllerV4 extends ControllerV4 {

    private int defaultValue = 25;
    private int value;
    @Override
    int get()    {
        return value;
    }
    void set(int value) {
        System.out.println("Old value of VolumeController \t"+this.value);
        this.value = value;
        System.out.println("New value of VolumeController \t"+this.value);
    }
    @Override
    public void setDefault() {
        set(defaultValue);
    }

    @Override
    public void checkForDriverUpdate()    {
        System.out.println("Checking driver update for VolumeController .... Done");
    }
}
class  BrightnessControllerV4 extends ControllerV4 {

    private int defaultValue = 50;
    private int value;
    @Override
    int get()    {
        return value;
    }
    @Override
    void set(int value) {
        System.out.println("Old value of BrightnessController \t"+this.value);
        this.value = value;
        System.out.println("New value of BrightnessController \t"+this.value);
    }

    @Override
    public void setDefault() {
        set(defaultValue);
    }

    @Override
    public void checkForDriverUpdate()    {
        System.out.println("Checking driver update for BrightnessController .... Done");
    }
}
class ColourControllerV4 extends ControllerV4 {

    private int defaultValue = 40;
    private int value;
    @Override
    int get()    {
        return value;
    }
    void set(int value) {
        System.out.println("Old value of ColourController \t"+this.value);
        this.value = value;
        System.out.println("New value of ColourController \t"+this.value);
    }
    @Override
    public void setDefault() {
        set(defaultValue);
    }

    @Override
    public void checkForDriverUpdate()    {
        System.out.println("Checking driver update for ColourController .... Done");
    }
}
class ResetFunctionV4 {

    private List<OnReset> controllers = null;

    ResetFunctionV4(List<OnReset> controllers)  {
        this.controllers = controllers;
    }
    void onReset()    {
        for (OnReset onreset :this.controllers)  {
            onreset.setDefault();
        }
    }
}
class InitializeDeviceV4 {

    private List<OnStart> controllers = null;

    InitializeDeviceV4(List<OnStart> controllers)  {
        this.controllers = controllers;
    }
    void initialize()    {
        for (OnStart onStart :this.controllers)  {
            onStart.checkForDriverUpdate();
        }
    }
}
/*
*       so on
*       There can be n number of controllers
*
* */
public class TvApplicationV4 {
    public static void main(String[] args)  {
        VolumeControllerV4 volumeControllerV4 = new VolumeControllerV4();
        BrightnessControllerV4 brightnessControllerV4 = new BrightnessControllerV4();
        ColourControllerV4 colourControllerV4 = new ColourControllerV4();
        List<ControllerV4> controllerV4s = new ArrayList<>();
        controllerV4s.add(brightnessControllerV4);
        controllerV4s.add(volumeControllerV4);
        controllerV4s.add(colourControllerV4);

        List<OnStart> controllersToInitialize = new ArrayList<>();
        controllersToInitialize.addAll(controllerV4s);
        InitializeDeviceV4 initializeDeviceV4 = new InitializeDeviceV4(controllersToInitialize);
        initializeDeviceV4.initialize();

        List<OnReset> controllersToReset = new ArrayList<>();
        controllersToReset.addAll(controllerV4s);
        ResetFunctionV4 resetFunctionV4 = new ResetFunctionV4(controllersToReset);

        OUTER: while(true) {
            Scanner sc=new Scanner(System.in);
            System.out.println(" Enter your option \n Press 1 to increase volume \n Press 2 to decrease volume");
            System.out.println(" Press 3 to increase brightness \n Press 4 to decrease brightness");
            System.out.println(" Press 5 to increase color \n Press 6 to decrease color");
            System.out.println(" Press 7 to reset TV \n Press any other Button to shutdown");
            int button = sc.nextInt();
            switch (button) {
                case  1:    {
                    volumeControllerV4.adjust(5);
                    break;
                }
                case 2: {
                    volumeControllerV4.adjust(-5);
                    break;
                }
                case  3:    {
                    brightnessControllerV4.adjust(5);
                    break;
                }
                case 4: {
                    brightnessControllerV4.adjust(-5);
                    break;
                }
                case  5:    {
                    colourControllerV4.adjust(5);
                    break;
                }
                case 6: {
                    colourControllerV4.adjust(-5);
                    break;
                }
                case 7: {
                    resetFunctionV4.onReset();
                    break;
                }
                default:
                    System.out.println("Shutting down...........");
                    break OUTER;
            }

        }
    }
}

现在你面临的所有问题都得到了解决,你意识到通过使用继承和多态,你可以

  1. 保持应用程序的各个部分松散耦合。(重置或驱动程序更新功能组件不需要了解实际的控制器类(音量、亮度和颜色),任何实现 OnReset 或 OnStart 的类都可以接受重置或驱动程序更新功能组件分别)。
  2. 应用增强变得更容易。(新添加控制器不会影响重置或驱动程序更新功能组件,现在添加新的非常容易)
  3. 保留抽象层。(现在重置功能只能看到控制器的 setDefault 方法,重置功能只能看到控制器的 checkForDriverUpdate 方法)

希望这可以帮助 :-)

于 2018-05-06T17:18:06.607 回答
4

重载是当您定义 2 个名称相同但参数不同的方法时

覆盖是您通过子类中具有相同名称的函数更改基类的行为的地方。

因此,多态性与覆盖有关,但与真正的重载无关。

但是,如果有人对“什么是多态性?”这个问题给了我一个简单的“覆盖”答案。我会要求进一步解释。

于 2008-09-30T19:35:14.537 回答
4

多态性是对象以多种形式出现的能力。这涉及使用继承和虚函数来构建可以互换的对象系列。基类包含虚函数的原型,可能未实现或具有应用程序要求的默认实现,并且各个派生类各自以不同的方式实现它们以影响不同的行为。

于 2008-09-30T19:36:05.253 回答
4

两者都不:

重载是当你有相同的函数名但接受不同的参数时。

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

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

在 Java 中,您可以通过 collections 库看到很多多态性:

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() 来匹配参数。

于 2008-09-30T19:44:34.497 回答
3

什么是多态性?

来自java教程

多态性的字典定义是指生物学中的一个原理,其中一个有机体或物种可以有许多不同的形式或阶段。这个原则也可以应用于面向对象的编程和像 Java 语言这样的语言。一个类的子类可以定义它们自己独特的行为,并且共享一些与父类相同的功能。

通过考虑示例和定义,应该接受覆盖的答案。

关于您的第二个查询:

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

它应该被称为覆盖。

查看此示例以了解不同类型的覆盖。

  1. 基类没有提供实现,子类必须覆盖完整的方法 - (抽象)
  2. 基类提供默认实现,子类可以改变行为
  3. super.methodName()子类通过调用作为第一条语句向基类实现添加扩展
  4. 基类定义算法的结构(模板方法),子类将覆盖算法的一部分

代码片段:

import java.util.HashMap;

abstract class Game implements Runnable{

    protected boolean runGame = true;
    protected Player player1 = null;
    protected Player player2 = null;
    protected Player currentPlayer = null;

    public Game(){
        player1 = new Player("Player 1");
        player2 = new Player("Player 2");
        currentPlayer = player1;
        initializeGame();
    }

    /* Type 1: Let subclass define own implementation. Base class defines abstract method to force
        sub-classes to define implementation    
    */

    protected abstract void initializeGame();

    /* Type 2: Sub-class can change the behaviour. If not, base class behaviour is applicable */
    protected void logTimeBetweenMoves(Player player){
        System.out.println("Base class: Move Duration: player.PlayerActTime - player.MoveShownTime");
    }

    /* Type 3: Base class provides implementation. Sub-class can enhance base class implementation by calling
        super.methodName() in first line of the child class method and specific implementation later */
    protected void logGameStatistics(){
        System.out.println("Base class: logGameStatistics:");
    }
    /* Type 4: Template method: Structure of base class can't be changed but sub-class can some part of behaviour */
    protected void runGame() throws Exception{
        System.out.println("Base class: Defining the flow for Game:");  
        while ( runGame) {
            /*
            1. Set current player
            2. Get Player Move
            */
            validatePlayerMove(currentPlayer);  
            logTimeBetweenMoves(currentPlayer);
            Thread.sleep(500);
            setNextPlayer();
        }
        logGameStatistics();
    }
    /* sub-part of the template method, which define child class behaviour */
    protected abstract void validatePlayerMove(Player p);

    protected void setRunGame(boolean status){
        this.runGame = status;
    }
    public void setCurrentPlayer(Player p){
        this.currentPlayer = p;
    }
    public void setNextPlayer(){
        if ( currentPlayer == player1) {
            currentPlayer = player2;
        }else{
            currentPlayer = player1;
        }
    }
    public void run(){
        try{
            runGame();
        }catch(Exception err){
            err.printStackTrace();
        }
    }
}

class Player{
    String name;
    Player(String name){
        this.name = name;
    }
    public String getName(){
        return name;
    }
}

/* Concrete Game implementation  */
class Chess extends Game{
    public Chess(){
        super();
    }
    public void initializeGame(){
        System.out.println("Child class: Initialized Chess game");
    }
    protected void validatePlayerMove(Player p){
        System.out.println("Child class: Validate Chess move:"+p.getName());
    }
    protected void logGameStatistics(){
        super.logGameStatistics();
        System.out.println("Child class: Add Chess specific logGameStatistics:");
    }
}
class TicTacToe extends Game{
    public TicTacToe(){
        super();
    }
    public void initializeGame(){
        System.out.println("Child class: Initialized TicTacToe game");
    }
    protected void validatePlayerMove(Player p){
        System.out.println("Child class: Validate TicTacToe move:"+p.getName());
    }
}

public class Polymorphism{
    public static void main(String args[]){
        try{

            Game game = new Chess();
            Thread t1 = new Thread(game);
            t1.start();
            Thread.sleep(1000);
            game.setRunGame(false);
            Thread.sleep(1000);

            game = new TicTacToe();
            Thread t2 = new Thread(game);
            t2.start();
            Thread.sleep(1000);
            game.setRunGame(false);

        }catch(Exception err){
            err.printStackTrace();
        }       
    }
}

输出:

Child class: Initialized Chess game
Base class: Defining the flow for Game:
Child class: Validate Chess move:Player 1
Base class: Move Duration: player.PlayerActTime - player.MoveShownTime
Child class: Validate Chess move:Player 2
Base class: Move Duration: player.PlayerActTime - player.MoveShownTime
Base class: logGameStatistics:
Child class: Add Chess specific logGameStatistics:
Child class: Initialized TicTacToe game
Base class: Defining the flow for Game:
Child class: Validate TicTacToe move:Player 1
Base class: Move Duration: player.PlayerActTime - player.MoveShownTime
Child class: Validate TicTacToe move:Player 2
Base class: Move Duration: player.PlayerActTime - player.MoveShownTime
Base class: logGameStatistics:
于 2016-09-16T13:37:09.097 回答
2

重载一词是指具有相同名称的事物的多个版本,通常是具有不同参数列表的方法

public int DoSomething(int objectId) { ... }
public int DoSomething(string objectName) { ... }

所以这些函数可能会做同样的事情,但您可以选择使用 ID 或名称来调用它。与继承、抽象类等无关。

正如您在问题中描述的那样,覆盖通常是指多态性

于 2008-09-30T19:33:12.093 回答
2

我认为你们正在混合概念。多态性是对象在运行时表现不同的能力。为此,您需要两个先决条件:

  1. 后期装订
  2. 遗产。

话虽如此,重载与覆盖的含义不同,具体取决于您使用的语言。例如在 Java 中不存在覆盖而是重载。子类中提供了对其基类具有不同签名的重载方法。否则它们将被覆盖(请注意,我的意思是现在无法从对象外部调用您的基类方法)。

然而,在 C++ 中并非如此。任何重载的方法,无论签名是否相同(不同的数量,不同的类型)都会被覆盖。也就是说,显然,当从子类对象外部调用时,基类的方法在子类中不再可用。

所以答案是在谈到 Java 时使用重载。在任何其他语言中可能与在 c++ 中发生的情况不同

于 2012-02-24T12:52:30.790 回答
2

覆盖更像是通过声明与上层方法(超级方法)具有相同名称和签名的方法来隐藏继承的方法,这为类添加了多态行为。换句话说,选择要调用的最高级别方法的决定将在运行时而不是在编译时做出。这就引出了接口和实现的概念。

于 2013-04-26T12:06:22.053 回答
2

多态性是对象的多种实现,或者您可以说对象的多种形式。假设您将类Animals作为抽象基类,并且它有一个称为movement()定义动物移动方式的方法。现在实际上我们有不同种类的动物,它们的移动方式也不同,有些有 2 条腿,有些有 4 条,有些没有腿,等等。要定义movement()地球上每种动物的不同之处,我们需要应用多态性。但是,您需要定义更多的类,即类Dogs Cats Fish等。然后您需要从基类扩展这些类,并根据您拥有的每种动物使用新的运动功能Animals覆盖其方法。movement()你也可以使用Interfaces实现这一目标。这里的关键字是覆盖,重载是不同的,不被认为是多态。通过重载,您可以定义多个“同名”但在同一对象或类上具有不同参数的方法。

于 2013-09-15T22:37:13.643 回答
1

就其含义而言,多态性更有可能......在java中覆盖

这都是关于同一对象在不同情况下的不同行为(在编程方式中......你可以调用不同的参数)

我认为下面的示例将帮助您理解......虽然它不是纯 java 代码......

     public void See(Friend)
     {
        System.out.println("Talk");
     }

但是如果我们改变 ARGUMENT ...... BEHAVIOR 将会改变......

     public void See(Enemy)
     {
        System.out.println("Run");
     }

人(这里是“对象”)是一样的......

于 2012-09-11T14:04:44.593 回答
0

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

无论如何,使用其他语言(例如 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 = 新狗();狗 b = 新狗();

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

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

于 2008-09-30T19:50:18.837 回答
0
import java.io.IOException;

class Super {

    protected Super getClassName(Super s) throws IOException {
        System.out.println(this.getClass().getSimpleName() + " - I'm parent");
        return null;
    }

}

class SubOne extends Super {

    @Override
    protected Super getClassName(Super s)  {
        System.out.println(this.getClass().getSimpleName() + " - I'm Perfect Overriding");
        return null;
    }

}

class SubTwo extends Super {

    @Override
    protected Super getClassName(Super s) throws NullPointerException {
        System.out.println(this.getClass().getSimpleName() + " - I'm Overriding and Throwing Runtime Exception");
        return null;
    }

}

class SubThree extends Super {

    @Override
    protected SubThree getClassName(Super s) {
        System.out.println(this.getClass().getSimpleName()+ " - I'm Overriding and Returning SubClass Type");
        return null;
    }

}

class SubFour extends Super {

    @Override
    protected Super getClassName(Super s) throws IOException {
        System.out.println(this.getClass().getSimpleName()+ " - I'm Overriding and Throwing Narrower Exception ");
        return null;
    }

}

class SubFive extends Super {

    @Override
    public Super getClassName(Super s) {
        System.out.println(this.getClass().getSimpleName()+ " - I'm Overriding and have broader Access ");
        return null;
    }

}

class SubSix extends Super {

    public Super getClassName(Super s, String ol) {
        System.out.println(this.getClass().getSimpleName()+ " - I'm Perfect Overloading ");
        return null;
    }

}

class SubSeven extends Super {

    public Super getClassName(SubSeven s) {
        System.out.println(this.getClass().getSimpleName()+ " - I'm Perfect Overloading because Method signature (Argument) changed.");
        return null;
    }

}

public class Test{

    public static void main(String[] args) throws Exception {

        System.out.println("Overriding\n");

        Super s1 = new SubOne(); s1.getClassName(null);

        Super s2 = new SubTwo(); s2.getClassName(null);

        Super s3 = new SubThree(); s3.getClassName(null);

        Super s4 = new SubFour(); s4.getClassName(null);

        Super s5 = new SubFive(); s5.getClassName(null);

        System.out.println("Overloading\n");

        SubSix s6 = new SubSix(); s6.getClassName(null, null);

        s6 = new SubSix(); s6.getClassName(null);

        SubSeven s7 = new SubSeven(); s7.getClassName(s7);

        s7 = new SubSeven(); s7.getClassName(new Super());

    }
}
于 2015-07-16T13:11:24.960 回答