继承和多态

  • 继承和多态是什么?
  • 继承实现
  • 方法覆盖
  • 多态实现
  • instanceof
  • 子类构造方法
  • 抽象类


继承和多态是什么?

继承是对已有类的域和方法的复用,并可在此基础上,添加新的操作。

多态是一个变量可以指示多种实际类型的现象,在运行时能够自动选择调用哪个方法的现象称为动态绑定。

继承实现

继承通过在类定义后面添加 extends 类名 实现,Java只支持单继承

public class Dog {
    private int cost;

    public void setCost(int cost) {
        this.cost = cost;
    }
}

class LuckyDog extends Dog {
    private String name;

    public void setName(String name) {
        this.name = name;
    }
}

继承后,子类会获得除父类构造方法外的所有成员方法和成员变量,如下,LuckyDog继承了Dog的cost和setCost()方法,并新增了name和setName()方法:

Dog dog = new Dog();
dog.setCost(1000);
LuckyDog luckyDog = new LuckyDog();
luckyDog.setName("luckyDog");
luckyDog.setCost(2000);

方法覆盖

子类可以通过重写父类的方法覆盖原来的方法,覆盖时子类方法的可见性不能低于父类方法,子类方法访问父类方法或属性需要使用super关键字,如LuckyDog在Dog的基础上贵1000:

public class Dog {
    private int cost = 1000;

    public int getCost() {
        return cost;
    }
}

class LuckyDog extends Dog {

    public int getCost() {
        return super.getCost() + 1000;
    }
}

多态实现

多态实现的前提是父类子类拥有相同的方法,即存在方法覆盖,如上面的实例,用父类Dog的变量luckyDog指向子类对象new LuckyDog(),调用getCost()方法将打印2000,但多态情况下不能使用子类独有的方法

Dog dog = new Dog();
System.out.println(dog.getCost());
Dog luckyDog = new LuckyDog();
System.out.println(luckyDog.getCost());

instanceof

在下面的继承结构中

public class Dog {

}

class LuckyDog extends Dog {

    public int getCost() {
        return 1000;
    }
}

通过多态,子类数组可转为父类数组,但此时,子类变量luckyDogs和父类变量dogs指向同一个数组:

LuckyDog[] luckyDogs = new LuckyDog[3];
Dog[] dogs = luckyDogs;

若赋值

dogs[0] = new Dog();

就会误将Dog对象存储到LuckyDog对象的数组中,当调用子类特有方法时会产生错误,如

for (int i = 0; i < luckyDogs.length; i++) {
     luckyDogs[i].getCost();
}

将父类转为子类时,可能会造成错误,这时需要用instanceof关键字判断

for (int i = 0; i < luckyDogs.length; i++) {
    if (luckyDogs[i] instanceof LuckyDog) {
        luckyDogs[i].getCost();
    }
}

子类构造方法

如果子类构造方法没有调用父类的构造方法,则会隐式自动调用父类无参构造方法,同时子类构造方法可以通过super显式调用父类的构造方法(必须放在第一句):

public class Dog {
    private int cost;

    public Dog() {

    }

    public Dog(int cost) {
        this.cost = cost;
    }
}

class LuckyDog extends Dog {
    public LuckyDog() {
        //super();
    }

    public LuckyDog(int cost) {
        super(cost);
    }
}

抽象类

当一个方法对父类没有意义,但其对所有具体子类都有意义(如下:抽象的Person没有名字可以返回),可以通过abstract关键字将其改为抽象方法

拥有一个或多个抽象方法的类为抽象类,若其子类不是抽象类,就应该实现抽象父类中的所有抽象方法

abstract class Person{
    private String name;
    abstract String getName();
}

不含抽象方法的类也可申明为抽象类,抽象类不能实例化,即不能通过new创建抽象类实例,但可以引用其子类实例