继承的基本思想是基于某个父类的扩展,制定一个新的子类,子类可以继承父类的属性和方法,也可以增加原来父类不具备的属性和方法,或者重写父类中的某些方法。
1.子类继承父类的用法
Java中使用extends关键字标识两个类的继承关系
来看代码例子:
子类继承父类,调用父类的构造方法和成员方法,并重写父类方法,修改方法的权限和返回值类型。
class Test {
public Test() { //构造方法
//SomeSentence
}
protected void doSomething() { //成员方法
//SomeSentence
}
protected Test dolt() {
return new Test();
}
}class Test2 extends Test{
public Test2(){
super(); //调用父类的构造方法
super.doSomething(); //调用父类的成员方法
}
public void doSomethingnew(){ //新增方法
//SomeSentence
}
public void doSomething(){ //重写父类方法,可将doSomething方法的权限从protected改为public
//SomeSentence
}
protected Test2 dolt(){ //重写父类方法,方法返回值类型为Test2类型
return new Test2();
}
}
调用、重写父类方法:
如果在重写的方法中调用了父类的相同方法,必须要通过super关键字显示的指明出来。
super的作用主要在下面三种情况下:
1)调用父类被子类重写的方法;
2)调用父类被子类重定义的字段(被隐藏的成员变量);
3)调用父类的构造方法;
其他情况,由于子类自动继承了父类相应属性方法,关键字super可以不显示写出来。
注意:子类没有权限调用父类中被修饰为private的方法,只可以调用父类中修饰为public和protected的成员方法。
修改父类方法权限:
继承并不只是扩展父类的功能,还可以重写父类的成员方法,重写就是在子类中保留父类成员方法的名称,重写成员方法的实现内容,更改成员方法的存储权限。例如上例中就把将doSomething方法的权限从protected改为public。
注意:当重写父类方法时,修改成员方法的权限智能从小改到大,反过来是不行的。上例中重写doSomething方法时只能将权限从protected改为public,不能修改为private。即重写不能降低方法的修饰权限范围。
子类实例化对象:
当实例化子类对象时,父类对象也会相应被实例化。
在实例化子类对象时,Java编译器会在子类的构造方法中自动调用父类的无参构造方法。
来看代码例子:
public class Parent { //父类 Parent(){ System.out.println("调用父类的Parent()构造方法"); } } class SubParent extends Parent { //继承Parent类 SubParent() { System.out.println("调用子类的SubParent()构造方法"); } } class Subroutine extends SubParent { //继承SubParent类 Subroutine() { System.out.println("调用子类的Subroutine()构造方法"); } public static void main(String[] args) { Subroutine s = new Subroutine(); //实例化子类对象 } }结果:
调用父类的Parent()构造方法
调用子类的SubParent()构造方法
调用子类的Subroutine()构造方法
从上述例子可以看出,实例化子类对象时会调用父类的构造方法,而调用构造方法的顺序为“顶层父类 --> 子类的上一级父类 --> 子类。也就是说实例化子类对象时会先完成父类对象的实例化,然后再实例化子类对象。
说明:实例化子类对象时,父类的无参构造方法将被自动调用,但是有参构造方法并不能被自动调用,需要super关键字显式地调用父类的构造方法。
2.Object类
在Java中,Object类是所有类的父类。其他类均继承于Object类,由于所有类都是Object类的子类,所以在定义类时省略了extends Object关键字,正因为如此,任何类都可以重写Object类中的方法。
注意:Object类中的getClass(),notify(),notifyAll(),wait()等方法不能被重写,因为这些方法被定义为final类型。
3.对象类型的转换
将子类对象看作父类对象,被称为“向上转型”,向上转型是从一个具体的类到较抽象的类的转换,因此总是安全的。反之为向下转型,向下转型通常会出现问题。
来看代码例子:
class Birds {
public static void fly(Birds q) {
System.out.println("Birds can fly.");
}
}
public class Dove extends Birds {
public static void main(String[] args) {
Dove p = new Dove(); //实例化子类对象
fly(p); //调用父类方法
Birds a = new Dove(); //把子类对象赋值给父类类型变量
fly(a);
// Dove b = a; //将父类对象赋给子类对象,这种写法是错误的
Dove b = (Dove) a; //如果需要将父类对象赋给子类对象,则必须强转为子类类型
}
}
将父类对象直接赋值给子类会报编译错误,因为父类对象不一定是子类的实例。如果对象需要向下转型,则需要使用强转。
在强转之前可用instanceof关键字来判断父类对象是否为子类的一个实例,如果是则强转。
if (a instanceof Dove) { //判断是否为子类的一个实例
Dove b = (Dove) a; //如果需要将父类对象赋给子类对象,则必须强转为子类类型
}