Java基础教程 - 7 面向对象-4

更好的阅读体验:点这里www.doubibiji.com
更好的阅读体验:点这里www.doubibiji.com
更好的阅读体验:点这里www.doubibiji.com

7 面向对象

7.6 多态

1 什么是多态

多态就是多种状态,同一个类型的父类型对象,因为指向的是不同的子对象,而表现出的不同的状态。

所以多态是建立在继承的基础之上的。

举个栗子:

class Bird {
    public void tweet() {}
}

class Sparrow extends Bird {
    public void tweet() {
        System.out.println("我会啾啾叫");
    }
}

class Pigeon extends Bird {
    public void tweet() {
        System.out.println("我会咕咕叫");
    }
}

public class ExtendTest {
    public static void main(String[] args) {
        Bird bird1 = new Sparrow(); // 创建一个麻雀对象
        Bird bird2 = new Pigeon(); // 创建一个鸽子对象

        bird1.tweet();
        bird2.tweet();
    }
}

上面麻雀类和鸽子类都继承自鸟类,然后创建了一个麻雀对象和鸽子对象,都赋给了鸟类,通过两个对象分别调用 tweet() 方法。

执行结果:

我会啾啾叫
我会咕咕叫

虽然两个都是鸟类的变量,执行的都是 tweet() 方法,但是因为是不同的子类对象,却得到不同的结果。

以父类做定义声明,以子类做实际的工作,用于获取同一个行为的不同状态,这就是多态。

那也没看出多态有什么用啊。

多态的作用:

  • 提高代码的维护性
  • 提高代码的扩展性
  • 把不同的子类对象当做父类来看待,可以屏蔽不同子类对象之间的差异,写出通用的代码,以适应需求的不断变化。

2 多态的使用

说了那么多,有点虚,举个栗子:

实现一个功能:学生做交通工具去某个地方,交通工具可能是汽车、飞机。

先定一个汽车类:

传入一个目的地,就可以开车去了。

class Car {
    public void run(String destination) {
        System.out.println("开车去->" + destination);
    }
}

再定义一个飞机类:

class Plane {
    public void fly(String destination) {
        System.out.println("飞去->" + destination);
    }
}

然后定义一个学生类:

class Student {
    public void goTo(Object vehicle, String destination) {	// 传入交通工具
        if (vehicle instanceof Car) {			// 判断交通工具的类型,然后调用交通工具的方法
            Car car = (Car) vehicle;
            car.run(destination);
        } else if (vehicle instanceof Plane) {
            Plane plane = (Plane) vehicle;
            plane.fly(destination);
        }
    }
}

学生类有一个 goTo() 方法,接收交通工具和目的地,然后在方法中判断交通工具的类型,然后调用交通工具的方法。

调用代码:

public class ObjectTest {
    public static void main(String[] args) {
        Student stu = new Student();
        Car car = new Car();
        Plane plane = new Plane();

        stu.goTo(car, "北京");
        stu.goTo(plane, "新疆");
    }
}

执行结果:

开车去->北京
飞去->新疆

上面的代码可以实现功能,但是不易于扩展,如果我们现在增加一个交通工具火车,则还需要修改 Student 类的 goTo() 方法,针对新的交通工具来处理,因为学生类和汽车、飞机类直接存在依赖关系,耦合性高。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这样是违反了设计原则中的开闭原则,对扩展是开放的,对修改是封闭的,也就是允许在不改变它代码的前提下变更它的行为。

所以上面的代码扩展性就比较差了,那么怎么来优化代码,降低代码的耦合性呢?

这就需要用到多态了。

首先定义一个父类Vehicle(交通工具类),并定义一个transport()方法,都是交通工具,都是运输功能嘛。

然后让Car类和Plane类都继承这个父类,因为不同的子类运输方式不一样,所以子类需要重写父类的方法,实现自己的功能。

class Vehicle {
    void transport(String destination) {}
}

class Car extends Vehicle {
    public void transport(String destination) {
        System.out.println("开车去->" + destination);
    }
}

class Plane extends Vehicle {
    public void transport(String destination) {
        System.out.println("飞去->" + destination);
    }
}

然后修改学生类:

class Student {
    public void goTo(Vehicle vehicle, String destination) {	// 传入交通工具
        vehicle.transport(destination);
    }
}

学生类只需要调用交通工具的运输功能就可以了。

调用的代码不变:

public class ObjectTest {
    public static void main(String[] args) {
        Student stu = new Student();
        Car car = new Car();
        Plane plane = new Plane();

        stu.goTo(car, "北京");
        stu.goTo(plane, "新疆");
    }
}

执行结果:

开车去->北京
飞去->新疆

上面的代码使用了多态,学生类与各个交通工具子类已经不直接产生关系,遵从了设置原则中的依赖倒置原则(程序依赖于抽象接口,不要依赖于具体实现)。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

此时如果新增一个火车的交通工具,不用再修改学生类的代码,代码耦合性大大降低。

3 抽象类

什么是抽象类?

含有抽象方法的类成为抽象类。

那什么是抽象方法?

抽象方法就是没有方法体,方法体为空的方法。


上面的 Vehicle 类中的 transport 方法,没有方法体,我们可以将它定义为一个抽象方法,在方法前面添加 abstract 关键字。

包含抽象方法的类必须是抽象类,所以类也必须添加 abstract 关键字,将 Vehicle 定义为抽象类。

abstract class Vehicle {
    abstract public void transport(String destination);
}

包含抽象方法的类必须是抽象类,但是抽象类中可以没有抽象方法。

举个栗子:

abstract class Vehicle {
    /**
     * 抽象方法
     */
    abstract public void transport(String destination);

    /**
     * 非抽象方法
     */
    public void test() {
        System.out.println("测试方法");
    }
}

抽象类是不能被实例化的,在开发中,都会提供抽象类的子类,通过子类来实例化对象。

子类继承抽象类需要实现(重写)抽象类中所有的抽象方法,如果有抽象方法没有实现,那么这个类也必须定义为抽象类。

抽象类有什么作用呢?

抽象类是不能被实例化的,也就是不能用来创建对象。一般抽象类都是作为父类使用的,父类用来确定有哪些方法,相当于用来确定设计的标准,用于对子类的约束。

子类用来实现父类的标准,负责具体的实现,配合多态使用,获得不同的工作状态。

4 接口

如果一个抽象类中的方法都是抽象方法,我们可以将这个抽象类定义成接口。

在 Java 中,定义接口使用 interface 关键字,和定义抽象类是不同的,而且接口中的方法都是 abstract public,所以可以省略 abstract 和 public 修饰。

另外,一个类通过 extends 来继承抽象类,但是是通过 implements 来实现接口的。

举个栗子:

// 定义一个抽象类
abstract class Bird {
    abstract public void tweet();
}

// 定义一个接口
interface Animal {
    void breathe();
}

// 定义一个接口
interface Helpful {
    void help();
}

class Sparrow extends Bird implements Animal, Helpful {
    void tweet() {
        System.out.println("我会啾啾叫");
    }

    public void breathe() {
        System.out.println("我要呼吸");
    }

    public void help() {
        System.out.println("会吃虫子");
    }
}

public class ObjectTest {
    public static void main(String[] args) {
        Animal animal = new Sparrow();
        animal.breathe();
    }
}

上面我们定义了一个抽象类 Bird ,和两个接口 AnimalHelpful

然后定义了一个 Sparrow 类作为子类继承 Bird 类,同时实现了 AnimalHelpful两个接口。此时才看出抽象类和接口的不同。

一个类只能有一个父类,但是可以有多个接口。一个类需要实现抽象类和接口中所有的抽象方法,否则编译会报错。

接口中只能定义常量和抽象方法,所以抽象类的作用主要是提供约束和规范,在后面的JDK高版本中,接口中也可以定义方法了。

结合前面多态的使用去理解,前面多态的使用中,使用的是父类来完成的,我们也可以使用接口来完成。

代码:

interface Vehicle {				// 定义交通工具的接口,所有的交通工具都需要实现该接口
    void transport(String destination);
}

class Car implements Vehicle {    // 需要实现交通工具接口
    public void transport(String destination) {
        System.out.println("开车去->" + destination);
    }
}

class Plane implements Vehicle {	// 需要实现交通工具接口
    public void transport(String destination) {
        System.out.println("飞去->" + destination);
    }
}

class Student {
    public void goTo(Vehicle vehicle, String destination) {		// 传入的参数是交通工具,交通工具都必须有transport()方法
        vehicle.transport(destination);
    }
}

public class ObjectTest {
    public static void main(String[] args) {
        Student stu = new Student();
        Car car = new Car();
        Plane plane = new Plane();

        stu.goTo(car, "北京");
        stu.goTo(plane, "新疆");
    }
}
  • 22
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

山石岐渡

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值