继承
继承是面向对象编程中一种非常强大的代码复用机制,即在已有基础上进行功能的拓展。
首先我们先看一下没有使用继承的两个类Person
类和Student
类。
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{
private String name;
private int age;
private int score;
public int getScore() {...}
public void setScore(int score) {...}
public String getName() {...}
public void setName(String name) {...}
public int getAge() {...}
public void setAge(int age) {...}
}
这时候我们很容易就看出来,
Studnet
类中很多功能和Person
类中一样,只是多了一个score
字段和getScore()
、setScore()
方法。那么我们怎样可以在Student
中不写重复的代码?这时候就用到了继承
。
然后我们再看一下用继承写的这两个类。
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{
private int score;
public int getScore() {...}
public void setScore(int score) {...}
}
继承
是通过extends
关键词来实现的。
通过两段代码的对比,我们很容易发现,继承可以实现代码的复用,即去除相同功能代码的重复书写,可以使Student
类在Person
类的基础上进行功能的拓展。
注意:子类自动获得了父类的所有字段,严禁定义和父类重名的字段!
在OOP术语中,我们把
Person
类称为超类(super class),父类(parent class),基类(base class)
Student
类称为子类(subclass),扩展类(extended class)
- 继承树
在Java中,我们没有明确写extends
的类,编译器会自动加上extends Object
。任何类,除了Object
,都会继承自某个类。
Java只允许一个class继承自一个类,因此,一个类有且仅有一个父类。只有Object特殊,没有父类。
Java允许单继承(B类继承A类),多重继承(C类继承B类,B类继承A类),不同类继承同一个类(B类继承A类,C类继承A类)。
但是,Java不支持多继承
(C类继承A类,C类继承B类)。
Java的特性:
- 子类拥有父类非private的属性、方法。
- 子类可以拥有自己的属性和方法,即子类可以对父类进行扩展。
- 子类可以用自己的方式实现父类的方法。
- 提高了类之间的耦合性(继承的缺点,耦合度高就会造成代码之间的联系越紧密,代码独立性越差)。
- protected
- 继承导致子类无法访问父类
private
字段或者private
方法,为了让子类可以访问父类的字段,我们可以把父类的private
改为protected
,用protected
修饰的字段可以被子类访问。 - 因此,
protected
关键词可以把字段和方法的访问权限控制在继承树内部,一个protected
字段或者方法可以被其子类,以及子类的子类所访问。
- super
super
关键字表示父类(超类)。子类引用父类字段时,可以用super.fieldName
。
- 向上转型
定义:把一个子类类型安全的变为父类类型的赋值,被称为向上转型(upcasting)。
例如:
Person p = new Student();
继承树是Student > Person > Object
。所以,可以把Student
类型转型成Person
或者更高层次的Object
。
- 向下转型
定义:如果把一个父类类型强制的转型成子类类型,就是向下转型(downcasting)。
例如:
Person p1 = new Student(); // upcasting , ok
Person p2 = new Person();
Student s1 = (Student) p1; //downcasting,ok
Student s2 = (Student) p2; //runtime error!
Person
类型p1
实际指向Student
实例,Person
类型p2
实际指向Person
实例。在向下转型的时候,把p1
转型成Student
会成功,是因为p1
确实指向Student
实例,把p2
转型成Student
会失败,因为p2
的实际类型是person
,不能把父类转变成子类,因为子类的功能比父类的多,多的功能无法凭空变出来。
因此,向下转型很可能会失败。失败的时候,Java虚拟机会报ClassCastException
。
- instanceof
instanceof
实际上是用来判断一个变量是否是指定类型,或者是这个类型的子类。如果一个引用变量为null
,那么对任何instanceof
的判断都为false
。
instanceof
主要是用来避免向下转型出错,可以先判断一个实例是否是某种类型。例如:
Person p = new Student();
if(p instanceof Student){
Student s = (Student)p;
}