从抽象 class 继承和从具体 class 继承有什么区别?为什么我们需要后者?

What is the difference between inherit from an abstract class and from a concrete class? Why would we need the latter?

我知道摘要是 class 其他东西的延伸 但为什么要扩展非抽象 class? 仅从抽象 classes 扩展通常是更好的约定吗,因为它们不能被实例化,所以它不会做奇怪的事情?

一个例子来说明为什么必须 abstract/not 抽象来显示区别会很棒。

恕我直言,您正在谈论两个正交的事物。

在前者中你想确保没有人可以实例化你的抽象class。再加上一些额外的好东西,比如声明一些常用方法。

在继承中,您正在扩展 class 以添加/更新一些 functionality.If 您是父级 class 可以实例化 - 您不需要将其抽象化。

在很多情况下,您都希望从具体的 classes 进行扩展。

考虑一个名为 Device 的 class。每个设备都有一个名称,可以处于三种状态,ONOFFINIT_STATE。每个设备可以转onoff.

public class Device {
    private String name;
    private static final int ON = 1;
    private static final int OFF = 0;
    private static final int DEVICE_INIT_STATE = -1;
    private int deviceStatus = DEVICE_INIT_STATE;

    public Device(String name) {
        this.name = name; 
    }

    public final void on() {
        if (deviceStatus==OFF || deviceStatus==DEVICE_INIT_STATE) {
            deviceStatus = ON;
            System.out.println(getName() + " turned on");
        } else {
            System.out.println(getName()+" is already on");
        }
    }

    public final void off() {
        if (deviceStatus==ON) {
            deviceStatus = OFF;
            System.out.println(getName() + " turned off");
        } else {
            System.out.println(getName()+" is not on");
        }
    }

    public void undo() {
        if (deviceStatus==ON) {
            off();
        } else if(deviceStatus==OFF){
            on();
        }
    }

    public String getName() {
        return name;
    }

    protected boolean isON() {
        return deviceStatus==ON;
    }
}

考虑一个 Stereo,它也是一个 Device,但具有其他功能,例如 openTraycloseTraysetCd,并且可以处于 5 种状态即 ONOFFTRAY_OPENTRAY_CLOSEINIT_STATE.

public class Stereo extends Device {

    private String cd;
    private static final int TRAY_OPEN = 1;
    private static final int TRAY_CLOSE = 0;
    private static final int TRAY_INIT_STATE = -1;
    protected int trayState = TRAY_INIT_STATE;

    public Stereo(String name) {
        super(name);
    }

    public void openTray() {
        if(!isON()) {
            System.out.println(getName()+" is not on");
        } else if(trayState==TRAY_CLOSE || trayState == TRAY_INIT_STATE) {
            trayState = TRAY_OPEN;
            System.out.println("Tray opened for "+getName());
        }  else {
            System.out.println(getName()+" tray is already open");
        }

    }

    public void closeTray() {
        if(!isON()) {
            System.out.println(getName()+" is not on");
        } else if(trayState==TRAY_OPEN) {
            trayState = TRAY_CLOSE;
            System.out.println("Tray closed for "+getName());
        } else {
            System.out.println(getName()+" tray is not open");
        }

    }

    public void undo() {
        if(trayState==TRAY_OPEN) {
            closeTray();
        } else if(trayState==TRAY_CLOSE) {
            openTray();
        }
    }

    public void setCd(String cd) {
        this.cd = cd;
    }

    public String getCd() {
        return cd;
    }


}

Stereo 继承了 Deviceonoff 方法。您可以实例化一个基本设备,例如灯泡,如下所示:

Device lightBulb = new Device("Living room light bulb");

另一方面,您可以按如下方式实例化立体声:

Stereo stereo = new Stereo("Stereo in my heart");

从上面的例子中可以看出,灯泡是一个基本的 Device,只能转动 onoff。另一方面,Stereo 是一种更特殊的 Device,它可以变成 onoff,但也有 openTraycloseTray功能。由于 StereoDevice,它继承了 Deviceonoff 方法。这是一个示例,其中 super class 有一个用例,它可以被实例化并且不需要是抽象的。