继承
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.pngJava只允许一个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;
}
网友评论