Java-基础-继承

2019-08-13  本文已影响0人  月沉眠love

继承

Java使用extends关键字来实现继承

class Person {
    private String name;
    private int age;

    public String getName() {...}
    public void setName(String name) {...}
    public int getAge() {...}
    public void setAge(int age) {...}
}

class Student extends Person {
    // 不要重复name和age字段/方法,
    // 只需要定义新增score字段/方法:
    private int score;

    public int getScore() { … }
    public void setScore(int score) { … }
}

在OOP的术语中,我们把Person称为超类(super class),父类(parent class),基类(base class),把Student称为子类(subclass),扩展类(extended class)。

1.继承树

注意到我们在定义Person的时候,没有写extends。在Java中,没有明确写extends的类,编译器会自动加上extends Object。所以,

任何类,除了Object,都会继承自某个类
屏幕快照 2019-08-13 上午12.17.01.png

Java只允许一个class继承自一个类,因此,一个类有且仅有一个父类。只有Object特殊,它没有父类。

2.protected

继承有个特点,就是子类无法访问父类的private字段或者private方法。例如,Student类就无法访问Person类的name和age字段:
这使得继承的作用被削弱了。为了让子类可以访问父类的字段,

我们需要把private改为protected。用protected修饰的字段可以被子类访问:
class Person {
    protected String name;
    protected int age;
}

class Student extends Person {
    public String hello() {
        return "Hello, " + name; // OK!
    }
}

3.super

super关键字表示父类(超类)。子类引用父类的字段时,可以用super.fieldName

public class Main {
    public static void main(String[] args) {
        Student s = new Student("Xiao Ming", 12, 89);
    }
}

class Person {
    protected String name;
    protected int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

class Student extends Person {
    protected int score;

    public Student(String name, int age, int score) {
        this.score = score;
    }
}
屏幕快照 2019-08-13 上午12.25.10.png

任何class的构造方法,第一行语句必须是调用父类的构造方法。如果没有明确地调用父类的构造方法,编译器会帮我们自动加一句super();,所以,Student类的构造方法实际上是这样:

class Student extends Person {
    protected int score;

    public Student(String name, int age, int score) {
        super(); // 自动调用父类的构造方法
        this.score = score;
    }
}

但是,Person类并没有无参数的构造方法,因此,编译失败。

class Student extends Person {
    protected int score;

    public Student(String name, int age, int score) {
        super(name, age); // 调用父类的构造方法Person(String, int)
        this.score = score;
    }
}
注意:即子类不会继承任何父类的构造方法。子类默认的构造方法是编译器自动生成的,不是继承的。

向上转型

这种把一个子类类型安全地变为父类类型的赋值,被称为向上转型(upcasting)

Person p = new Student(); 

3.向下转型

和向上转型相反,如果把一个父类类型强制转型为子类类型,就是向下转型(downcasting)

Person p1 = new Student(); // upcasting, ok
Person p2 = new Person();
Student s1 = (Student) p1; // ok
Student s2 = (Student) p2; // runtime error! ClassCastException!

把p2转型为Student会失败,因为p2的实际类型是Person,不能把父类变为子类,因为子类功能比父类多,多的功能无法凭空变出来。
因此,向下转型很可能会失败。失败的时候,Java虚拟机会报ClassCastException
Java提供了instanceof操作符,可以先判断一个实例究竟是不是某种类型:

Person p = new Student();
if (p instanceof Student) {
    // 只有判断成功才会向下转型:
    Student s = (Student) p; // 一定会成功
}

3.区分继承和组合

class Book {
    protected String name;
    public String getName() {...}
    public void setName(String name) {...}
}
class Student extends Book {
    protected int score;
}

显然,从逻辑上讲,这是不合理的,Student不应该从Book继承,而应该从Person继承。
,是因为Student是Person的一种,它们是is关系,而Student并不是Book。实际上Student和Book的关系是has关系。

具有has关系不应该使用继承,而是使用组合,即Student可以持有一个Book实例:

class Student extends Person {
    protected Book book;
    protected int score;
}
上一篇 下一篇

猜你喜欢

热点阅读