继承(inherit)
先上一段代码!
class A{
...
}
class B extends A{ //B类继承了A类
...
}
继承使用关键字extends,意为扩展的意思。extends关键字就是在构造新类派生于一个已存在的类。
基本思想
继承的基本思想就是基于已有的类创建新的类。
作用:继承已存在的类可以复用这个类的方法,而且可以在此基础上增加新的方法和字段,使新的类能够适应新的情况。
超类和子类
在继承中最关键的名词就是超类和子类了。已存在的类就是超类,而新类就是子类。
超类又可以称之为父类或者基类。子类又可以称之为派生类。
覆盖方法
super关键字
当我们想使用超类的方法时,可以利用super.方法名的格式来调用。
例如:
class Employee{
private double salary;
...
public double getSalary(){
return salary;
}
}
class Manager extends Employee{
private double bonus = 100; //经理的额外奖金
...
public double getSalary(){
return super.getSalary() + bonus;
}
}
上例中经理不同与普通员工之处有一个奖金,所以getSalary()方法需要改写也就是覆盖了员工类的getSalary方法。而如果直接返回salary + bonus的话是错误的,因为经理类不能直接访问员工类的salary字段(因为它是私有的),这是就要使用super关键字来解决这个问题。
子类构造器
由于子类的构造器不能访问父类的私有字段,所以必须通过一个构造器来初始化这些私有字段。那么就可以用特殊的super语法来调用这个构造器。
注意:使用super调用构造器的语句必须是子类构造器的第一条语句。
例如:
public class Person{
private int age;
private String name;
...
public Person(String name){
this.name = name;
}
...
}
public class Student extends Person {
private int score;
private int sno;
public Student(String name) {
super(name);
//含义:调用Person类中带有name参数的构造器。
}
...
}
提示:
如果子类的构造器没有显式地调用父类的构造器,那么会自动调用超类的无参构造器。如果超类没有无参构造器,并且子类中又没有显式地调用超类的其他构造器,那么就会报错。
多态
多态(ploymorphism)也是由于继承而产生出的一个概念。在Java中,对象变量是多态的,一个超类类型的变量既可以引用自己的对象,也可以引用任何一个子类的对象。
简单来说,任何超类对象都可以用子类对象来替换。
例如
class Employee{
...
}
class Manager extends Employee{
...
}
Employee e;
e = new Employee(...);
e = new Manager(...);
注意:
不能将超类的引用赋予子类的变量。
继承虽然可以提高代码的复用性,但同时也有缺点,它会提高使得程序的耦合度增高,因为当父类被修改,子类也会收到影响。所以有时会用final关键字来阻止继承发生。
阻止继承:final类和方法
- final类
当将一个类定义为final,则说明这个类不允许被扩展,不允许拥有任何子类。 - final方法
当将一个方法定义为final,则这个类中的这个final方法就不允许被子类覆盖这个方法。
(当一个类被定义为final时,其方法自动成为final方法,但不包括字段)
强制类型转换
进行强制类型转换的唯一原因是:要在暂时忽视对象的实际类型之后使用对象的全部功能。
强制类型转换允许将一个子类的引用赋给一个超类变量,但不允许将超类的引用赋给一个子类变量。
一个好习惯: 在强制类型转换之前,使用instanceof操作符查看是否能够成功转换。
例:
if ( staff[1] instanceof Manager ){
boss = (Manager) staff[1];
...
}
注意:
- 只能在继承层次内进行强制类型转换。
- 在将超类强制类型转换为子类之前,应该使用instanceof进行检查。
只要没有捕获ClassCastException(类型转换异常),程序就会终止。
一般情况下,尽量少使用强制类型转换和instanceof运算符。
写在最后:
那么什么时候使用继承呢?
当你确实需要一个继承关系,并且可以用"is a"来描述。