多态

多态

多态即对象可以表现出的多种形态。多态的技术基础是继承和接口的实现。程序的抽象体系就是多态的生存土壤。

多态即为向上转型

ublic abstract class Tools {

}
public interface Attackable {

}
public class Hammer extends Tools implements Attackable {
p
}

使用多态后程序成员的表现

成员变量和静态方法

  • 编译期:如果声明类型的类中不存在被访问的成员变量和静态方法,则编译失败。
  • 运行时:使用声明类型的类中的成员变量,调用声明类型中的静态方法。

即在多态下访问成员变量是来自等号左侧的类型。
在多态下调用的静态方法是等号左侧的类型。
注意:不推荐使用引用变量调用静态方法或访问静态变量,应使用类型名称调用或访问

实例方法

  • 编译期:如果声明类型的类中不存在被调用的实例方法,则编译失败。
  • 运行时:调用被实例化的类型中的实例方法。
    即在多态下调用实例方法,编译期看等号左侧类型中是否存在此方法,运行时调用等号右侧类型中的成员方法
public class Test {
    public static void main(String[] args) {
        Profession p1 = new Paladin();
        System.out.println(p1.grade);// 实例变量来自父类
        System.out.println(p1.maxGrade);// 静态变量来自父类
        System.out.println(p1.getName());// 实例方法调用子类的***
        System.out.println(p1.getWeaponName());// 静态方法调用父类的
        // 以下语句编译出错,因为在声明类中不存在addBlood()
        // p1.addBlood();
        
        Paladin p2 = new Paladin();
        System.out.println(p2.grade);// 实例变量来自子类
        System.out.println(p2.maxGrade);// 静态变量来自子类
        System.out.println(p2.getName());// 实例方法调用子类的
        System.out.println(p2.getWeaponName());// 静态方法调用子类的
    }
}

使用instanceof判断实例是否是某种类型

public abstract class Profession {
    int grade = 1;
    static int maxGrade = 60;
    
    public String getName() {
        return "这是一个抽象的职业";
    }
    
    public static String getWeaponName() {
        return "锤子";
    }
}
public class Paladin extends Profession {
    int grade = 55;
    static int maxGrade = 100;

    public String getName() {
        return "圣骑士";
    }

    public static String getWeaponName() {
        return "光铸之锤";
    }
    
    public void addBlood() {
        
    }
}
public class Warrior extends Profession {

}

多态的类型转换

引用类型的兼容类型

如果引用类型的对象在与多个类型进行instanceof运算后,都返回true,则说明此对象与这些类型是相兼容的,它们之间可以进行类型转换。而与对象进行instanceof运算后返回false的类型是与对象类型不兼容的,不能进行类型转换,如果强制转换,会得到java.lang.ClassCastException异常。

父类与子类、接口与实现类之间都是相兼容的类型。

向上转型和向下转型

子类对象向父类或实现的接口类型转换即向上转型,向上转型是安全的,是自动的。多态即向上转型的过程。

父类或实现的接口类向子类对象转换即向下转型,向下转型是不安全的,是强制的。

public abstract class Profession {
    
}
public interface DPS {

}
public interface Tank {

}
public interface Treat {

}
public class Paladin extends Profession implements DPS, Treat, Tank {

}
public class Rogue extends Profession implements DPS {

}
public class Warrior extends Profession implements DPS, Tank {

}
// 向上转型
public class Test01 {
    public static void main(String[] args) {
        Warrior warrior = new Warrior();
        Paladin paladin = new Paladin();
        Rogue rogue = new Rogue();

        DPS dps;
        Tank tank;
        Treat treat;

        // 三种职业子类都实现了DPS接口,都可以向上转型成为DPS
        dps = warrior;
        dps = paladin;
        dps = rogue;

        // 向上转型需要对象继承父类型或实现父接口
        tank = warrior;
        tank = paladin;
        // 否则向上转型是不成功的
        // Rogue没有实现Tank接口,不能进行向上转型
        // tank = rogue;
        
        treat = paladin;
        // treat = warrior;
        // treat = rogue;
        System.out.println("main方法执行完成");
    }
}

// 向下转型
public class Test02 {
    public static void main(String[] args) {
        DPS dps1 = new Warrior();
        DPS dps2 = new Paladin();
        DPS dps3 = new Rogue();

        Warrior warrior = (Warrior) dps1;
        Paladin paladin = (Paladin) dps2;
        Rogue rogue = (Rogue) dps3;
        
        warrior = (Warrior)dps3;
        
        System.out.println("main方法执行完成");
    }
}

向上转型与向下转型的使用时机

向上转型

  • 当不需要直接面对子类类型时,可以通过向上转型降低程序的耦合度
  • 使用父类的功能就能完成相应的需要

用更抽象的类型声明变量,用更具体的类型实例化对象,让抽象类型的变量引用具体类型的对象。

Person p1 = new Student();

向下转型

当需要使用子类的特殊行为时

注意:在不同程序场景下使用同一个子类的不同抽象类型或接口类型进行声明,可以避免发生向下转型。

你可能感兴趣的:(多态)