计应本的自考笔记(6)-Java继承与多态

496 阅读7分钟

对象继承和“is a”关系

就像“万物皆对象”口头禅说的一样,Java中类层次的树形结构,跟日常我们理解和描述大千世界是一样的。我们会把动物,先划分为脊椎动物、节肢动物和软体动物。然后在脊椎动物里面又分哺乳动物,哺乳动物又可以细分猫和狗。

对于动物的描述,从大到小,由宽泛到具体。大的更一般的类看作是父类。包含在其中的,具体的类是子类。

子类与父类的关系是:子类对象“is kind of/is a” 父类对象。这也就是面向对象的继承特性,通过继承,可以增加软件的可复用性,使得代码在类之间共享。

注意:“is a”与“has a”关系是不同的。比如狗,是动物的一种,也可以说动物中包含了狗。但发动机属于汽车,却不能说发动机是汽车的一种。

extends关键字

先统一下名词:继承/派生是面向对象的特性之一。子类继承自父类,子类也称为派生类,父类也称为基类或者超类。

比如我们现在要实现一个Employee(员工)类,一个Manager(管理)类。普通员工拥有员工编号、姓名、职称、职级、生日等属性,管理则是特别的员工,额外拥有管理组的属性,以及管理的若干个员工。

  • 员工类
public class Employee {
    private String name, jobTitle;
    private Date birthday;
    private int jobGrade;
}
  • 管理类
public class Manager extends Employee{
    private String group;
    private Employee[] subordinates;
}

由于Manager继承自Employee,也就拥有了普通员工的所有成员。增加了可维护性,子类是更个性化的存在,子类的改动也不会牵动到父类。

Object类

Object类是Java中所有类的直接或间接父类,处于类层次的最高点。

Object类提供了比如getClass()toString()以及equals()等基础方法。

关于判定对象是否相等有两种方式,一种是==运算符,判定对象引用是否相等;另一种是使用equals()方法,判定对象的类型,对象属性值是否相等。

单继承特性

上面提到,子类用extends关键字来继承父类,那能不能继承多个父类呢?答案是不行的。

由于多重继承是网状的关系,子类和父类都是多对多的关系,而子类的多个父类一旦有同名的属性或者方法,很容易造成子类实例的混乱。而单继承关系则是树状结构,如果需要多继承能力则可以通过接口来实现。

注意:子类可以继承所能继承的方法和成员变量,但不能继承构造函数。

对象转型

子类和父类的转型规则

Employee e = new Manager(),将子类的实例赋值给父类变量,这称为“对象转型(Casting)”。

变量可以赋值本类的实例,也可以只想子类的实例,这就是对象多态性的体现,但反过来不行。

对象引用转型的规则:

  • 沿着类层次向“上”转型总是合法的。比如Manager子类,转成Employee父类;
  • 向“下”转型,只能是沿着继承链的父类转子类,其他类是不允许的,且要使用显式转换;

instanceof

这时可能你会想了,变量e可以赋值Employee的实例对象,可以赋值Manager子类实例对象,我怎么知道具体是什么对象呢?我要知道是子类对象,才能访问它特有的属性和方法啊?答案就是instanceof运算符

System.out.println(e instanceof Manager); // true

Override(方法覆盖)

当父类的方法不能满足需求时,子类可以修改父类提供的方法,这称为方法覆盖/方法重写(Override)。这也是面向对象多态的特性。

Override的规则

  • 子类重写父类的方法,要使用相同的方法名以及参数列表。
  • 同时子类方法不能比父类方法的访问权限更严格,比如,弗雷方法的访问权限是public,那么子类方法则不能是private的修饰。还有。
  • 子类方法抛出的异常也不能比原方法多。

Override与Overload区别

如果方法名相同,但参数列表不同,则是Overload(方法重载)。Overload是发生在同一个类,而Override则发生在父类子类中。

super

如果子类想使用父类被隐藏的方法,可以通过super指针访问。调用super()可显式的调用父类的构造函数。

理解多态

多态,是面向对象语言的重要特性。Java规定了,多态的情况下,执行的是对象真实的类型(运行时类型)的方法,而不是声明类型(静态类型)的方法。

这里解释一下静态类型和动态类型:

  • 对象声明时称为静态类型,或者说引用类型。我们编写的代码编译时就确定下来的类型;
  • 而代码在运行过程中,指向的对象类型,称为动态类型,这是真正的类型;

final终极类、方法和属性

关键字final,既可以修饰类,也可以修饰类当中的属性和方法,被final修饰表示不能改变。final类不能被继承,不再拥有子类。final方法不能被重写;final变量,值不能被改变。

怎么会有要求不能被继承的类呢?有的,像Java.lang.String类就是如此,类的结构和功能都很完美了,用就完事了,你不用再扩展和补充。这样做的目的,是为了保证程序中,如果有指向String类的引用,那它就是真的String类型,而不是被改过的String子类。

final方法也是如此,同时final方法还利于优化,提高编译运行的效率。

通过final定义常量,应该是Java程序员最熟悉的操作了。值得注意的是,如果该常量是引用类型,那么不能再篡改引用地址,但可以对原对象的属性值的修改,或者进行扩展属性。

Abstract抽象类

设计程序的时候,需要创建某个类仅仅定义基本行为和属性,但又不宜在这个类就进行具体的实现,而是希望等子类根据实际情况再去实现这些方法。这种定义了方法,但没有方法的具体实现的类,称为抽象类,通过abstract关键字定义。抽象类中通过abstract定义的方法,称为抽象方法。

抽象类是用来进行继承的,所以不能直接实例化。

抽象类可以包含常规类能包含的任何成员方法,包括构造函数,通常也会包含抽象方法,但反过来常规类中不能定义抽象方法。

  • 抽象类Storage
abstract class Storage {
    int objectNum = 0;  // 存储了多少个对象
    Object storage[] = new Object[10];  // 存储容器

    abstract void put(Object obj);  // 存入方法
    abstract Object get();  // 获取方法
}
  • 常规类Stack
// 实现栈结构
public class Stack extends Storage {

    private int point = 0; // 指针

    @Override
    void put(Object obj) {
        storage[point++] = obj;
        objectNum++;
    }

    @Override
    Object get() {
        objectNum--;
        return storage[point];
    }
}
  • 常规类Queue
// 实现队列结构
public class Queue extends Storage{
    private int top = 0, bottom = 0;

    @Override
    void put(Object obj) {
        storage[top++] = obj;
        objectNum++;
    }

    @Override
    Object get() {
        objectNum--;
        return storage[bottom++];
    }
}

Interface接口

接口,是特殊的抽象类,可以看作是更纯粹的抽象类。它只规定了类的基本形式,接口中可以有成员变量,但系统会默认加上final和static关键字来修饰,所以必须对成员变量赋初始值,接口内的方法必须是抽象方法。

接口可以实现多继承特性,一个子类只能继承一个父类,但可以实现多个接口,使得代码具有更清晰的结构。

  • CharStorage接口
public interface CharStorage {
    void put(char c);
    char get();
}
  • CharStack类
public class CharStack implements CharStorage{

    private char member[] = new char[10];
    private int point = 0;

    @Override
    public void put(char c) {
        member[point] = c;
        point++;
    }

    @Override
    public char get() {
        point--;
        return member[point];
    }
}