多态基础

多态是指同一个行为,不同的子类表现出来不同的形式或形态。多态跟属性无关,多态指的是方法的多态,而不是属性的多态。下面参考一个案例:

public class Animal {
    public void shout(){
        System.out.println("叫。。。");
    }
}
public class Cat extends Animal{
    public void shout(){
        System.out.println("喵喵叫");
    }
    public void scratch(){
        System.out.println("挠人");
    }
}
public class Dog extends Animal{
    public void shout(){
        System.out.println("汪汪叫");
    }
    public void guard(){
        System.out.println("看家护院");
    }
}
public class Pig extends Animal{
    public void shout(){
        System.out.println("哼哼叫");
    }
    public void eat(){
        System.out.println("吃东西");
    }
}
public class Girl {
    public void play(Animal an){
        an.shout();
    }
}
public class Test {
    public static void main(String[] args) {
        Girl g = new Girl();
        Pig p = new Pig();
        Animal an = p;
        g.play(an);
    }
}

上面的代码,是多态的一种非常常见的应用场合:父类当方法的形参,然后传入的是具体的子类的对象,然后调用同一个方法,根据传入的子类的不同展现出来的效果也不同,构成了多态。

多态的要素:

  • 继承

  • 重写

  • 父类引用指向子类对象

    Pig p = new Pig();
    Animal an = p;
    

    上面代码合为一句是:

    Animal an = new Pig();
    

    等号左侧是编译器的类型,等号右侧是运行期的类型。

多态的好处:提高了代码的扩展性,符合面向对象的设计原则:开闭原则(扩展是开放的,修改是关闭的)。

向上转型和向下转型

public class Animal {
    int age;
    public void shout(){
        System.out.println("叫。。。");
    }
}
public class Pig extends Animal{
    double weight;
    public void shout(){
        System.out.println("哼哼叫");
    }
    public void eat(){
        System.out.println("吃东西");
    }
}
public class Test {
    public static void main(String[] args) {
        Pig p = new Pig();
        Animal an = p;
        an.shout();
        // an.eat(); 报错
        an.age = 10;
        // an.weight = 60.8; 报错
    }
}

上述代码中,有两行报错语句被注释掉了。之所以会报错是因为,对象 an 在编译期是 Animal 类型,而 Animal 类是没有 weight 属性和 eat() 方法的,它们都在 pig 类中。

如果一定要访问 weight 属性和 eat() 方法的话,就要将对象 an 向下转型:

public class Test {
    public static void main(String[] args) {
        Pig p = new Pig();
        Animal an = p; //向上转型
        an.shout();

        Pig pig = (Pig)an; //向下转型
        pig.eat(); 
        pig.age = 10;
        pig.weight = 60.8;
    }
}

在这里可以想起之前重写 euqals() 方法时的代码,也使用了向下转型:

public boolean equals(Object obj) { //Object obj = new Phone();
    Phone other = (Phone)obj; //向下转型
    if(this.getBrand()==other.getBrand()&&this.getPrice()==other.getPrice()&&this.getYear()==other.getYear()){
        return true;
    }
    return false;
}