Logo

郎哥编程

抽象类与接口

2021-06-13 256

学习目标:掌握抽象类和接口的创建及关系。

抽象类

用面向对象思想设计程序时,往往需要从众多的同类事物中抽取出它们的共同特征和行为封装为类,具体事物的不同特性和行为通过类的继承和多态来实现。

例如要设计一个汽车类程序,可以把汽车的共同特性和行为抽取出来封装为汽车类,轿车、卡车、巴士作为汽车类的子类。汽车类表示的是一个抽象的事物,并不代表某一具体的汽车,人们并不清楚汽车类表示的是轿车,还是卡车或巴士。

在程序设计过程中,并不需要将汽车类实例化为对象,只需要将汽车类的子类实例化为对象即可。在这种情况下,可以使用Java语言提供的抽象类,把汽车类声明为抽象类,抽象类不能实例化为对象,但可以用于继承和多态。

定义抽象类的语法如下:

public abstract class Car {
       // 抽象方法
public abstract void showCar();
}

抽象类的定义使用“abstract”关键字,抽象类和普通类一样,也有成员变量和成员方法。如果成员方法也使用“abstract”关键字修饰,这个成员方法称为抽象方法,抽象方法只有方法声明,没有方法体,抽象方法必须在继承的子类中实现。

抽象类本身不能实例化,继承抽象类的子类可以实例化,继承的子类需要全部实现抽象类的抽象方法,也就是重写抽象类的抽象方法。

案例1:创建抽象类Car(汽车父类),在抽象类中定义Car类的成员变量和showCar()抽象方法,并创建子类Truck类(卡车类)和Bus类(巴士类)。

建立PUnit7项目,在项目src目录下建立unit包。

在unit包下建立Car类,代码如下:

package unit;
public abstract class Car {
    // 成员变量,汽车制造商
    String  manufacturer;
    // 构造方法
    public Car(String manufacturer)
    {
        this.manufacturer = manufacturer;
    }
    // 抽象方法
    public abstract void showCar();
 
}

Car类是抽象类,在类内部定义了成员变量manufacturer,抽象方法showCar()和构造方法。

在Car类代码编辑窗口,将鼠标移动到定义类名的行,按下Alt+Enter键,弹出操作对话框,选择“Implement abstract class”命令。

10.jpg

在弹出的“Implement abstract class”对话框内,输入子类的名称,单击【OK】按钮即可创建Truck子类,该类会作为Car类的实现类。

01.jpg

在随后弹出的“Select Methods to Implement”对话框内,选择要实现的方法,单击【OK】按钮即可创建Truck子类。

02.jpg

Truck子类代码如下:

package unit;
public class Truck extends Car {
    public Truck(String manufacturer) {
        super(manufacturer);
    }
 
    @Override
    public void showCar() {
        System.out.println(this.manufacturer);
    }
}
用同样的方式新建Bus类,代码如下:
package unit;
public class Bus extends Car {
    public Bus(String manufacturer) {
        super(manufacturer);
    }
 
    @Override
    public void showCar() {
        // 输出汽车制造商
        System.out.println(this.manufacturer);
 
    }
}

Bus类的代码结构和Truck类的代码结构相同。

在unit包下新建测试类CarTest类,测试Truck类和Car类。代码如下:

package unit;
public class CarTest {
    public static void main(String[] args) {
        // 实例化Truck对象
        Truck  truck = new Truck("重汽公司制造");
        // 调用showCar()方法
        truck.showCar();
 
        // 实例化Bus对象
        Bus  bus = new Bus("巴士汽车公司制造");
        // 调用showCar()方法
        bus.showCar();
    }
 
}

程序执行结果如下图所示:

03.png

接口

当子类继承抽象类时,需要实现抽象类的所有抽象方法。这样会存在一个问题,如果有些子类并不需要实现抽象类的所有抽象方法时,就会造成代码冗余。另外抽象类为了满足实际问题的需要,会把更多的事物行为纳入到抽象类中作为抽象方法,反过来更加重了代码的冗余。

要解决代码冗余的问题,就需要用到Java语言提供的接口,接口是抽象类的延伸,接口中的所有方法都没有方法体,任何类都可以实现接口内的方法,一个类可以实现多个接口。可以把抽象类的抽象方法通过接口来声明,需要实现抽象方法的子类实现接口就可以了。这样就解决了代码冗余的问题。

接口不仅仅用于软件产品,也广泛应用于硬件产品。

例如,计算机上提供的USB接口,专门供USB设备使用,如U盘、USB风扇、USB鼠标、USB键盘等。计算机通过统一的USB接口来提高通用性,使计算机不再需要同时具备U盘专用接口、鼠标专用接口、键盘专用接口等。

再如,计算机的主板上提供的PCI插槽,也提供统一的设计规范,使得遵守这个规范的声卡、显卡、网卡都可以插在PCI插槽上,如下图所示:

04.png

上图中网卡、声卡、显卡内部结构都不相同,但可以把网卡、声卡、显卡都插在PCI插槽上,而不用担心哪个插槽是专门插那个卡的。

从上面两个例子可以看出,接口是一套标准规范,满足标准规范的外部设备都可以通过接口接入到系统。计算机设计师在设计USB接口时,规范USB的接入装置、供电电压、传输速率等。这些规范仅是规定了必须满足的功能和要求,但是却没有规定如何进行实现。

接口的具体实现由不同的USB设备厂商实现。这些USB设备厂商按照USB接口规范来生成产品,如U盘、USB鼠标等。

Java接口定义与实现

在Java中,使用interface关键字来定义接口。接口中的方法都只有声明,没有方法主体。例如:

//定义了一个PCI接口
public interface PCI {
//定义了一个开始方法
public void start();
//定义了一个结束的方法
public void stop();
}

Java接口中定义的方法都只有方法声明,没有方法体,也可以理解为接口中只能有抽象方法,具体的接口实现由实现类完成,这样就可以让不同的类遵守相同的规范,但又有自己的实现。

案例2:定义接口PCI,再分别定义声卡和显卡,来实现接口PCI规定的功能。

在PUnit7项目新建pci包,在pci包下新建PCI接口。用鼠标选择src目录下的pci包,单击鼠标右键,在弹出的菜单项列表中选择New ->Java Class命令,弹出“New Java Class”对话框,输入“PCI”接口名,并在类型列表中选择Interface。

06.jpg

PCI接口代码如下:

package pci;
public interface PCI {
    //定义了一个开始方法
    public void start();
    //定义了一个结束的方法
    public void stop();
}

PCI接口定义了两个方法,分别是start()方法和stop()方法,这两个方法只有方法声明,没有方法体。方法的实现由接口的实现类负责。

在pci包下新建SoundCard类(声卡类),该类实现PCI接口。具体方法如下:

在PCI接口代码编辑窗口,将鼠标移动到定义接口名的行,按下Alt+Enter键,弹出操作对话框,选择“Implement interface”命令。

07.jpg

在弹出的“Implement interface”对话框内,输入接口实现类的名称,单击【OK】按钮即可创建SoundCard类,该类会作为PCI接口的实现类。

08.jpg

在随后弹出的“Select Methods to Implement”对话框内,选择要实现的方法,单击【OK】按钮即可创建SoundCard类。

09.jpg

SoundCard类代码如下:

package pci;
public class SoundCard implements PCI {
    @Override
    public void start() {
        System.out.println("Du du...");
    }
 
    @Override
    public void stop() {
        System.out.println("Sound Stop!");
    }
}

类实现接口需要使用“implements”关键字,在“implements”关键字后面空格后紧跟接口名称。SoundCard类重写了PCI接口的两个方法。

在pci包下新建NetworkCard类(网卡类),该类实现PCI接口。NetworkCard类代码如下:

package pci;
public class NetworkCard implements PCI {
    @Override
    public void start() {
        System.out.println("Send...");
    }
 
    @Override
    public void stop() {
        System.out.println("Network stop!");
    }
}

NetworkCard类通过implements关键字来声明实现PCI接口,并分别实现了接口的start方法和stop方法。

在pci包下新建测试类InterfaceTest类,测试SoundCard类和NetworkCard类。InterfaceTest类代码如下:

package pci;
public class InterfaceTest {
    public static void main(String[] args) {
        // 实例化SoundCard对象
        SoundCard  soundCard = new  SoundCard();
        // 调用接口方法
        soundCard.start();
        soundCard.stop();
 
        // 实例化NetworkCard对象
        NetworkCard  netCard = new  NetworkCard();
        // 调用接口方法
        netCard.start();
        netCard.stop();
 
    }
}

程序执行结果如下图所示:

10.png

代码在线纠错(通义千问 qwen-max)

支持粘贴多个代码文件,提交后由阿里云通义千问自动分析代码漏洞、语法错误、逻辑问题并给出修改建议。
您已解锁 AI 代码纠错功能,可正常使用!

评论区

登录 后发表评论
暂无评论