多态的概述
什么是多态
同一个对象,在不同时刻表现出来的不同形态
多态的前提
- 要有继承或实现关系
- 要有方法的重写
- 要有父类引用指向子类对象
多态的具体实现
对象的多态是多态的核心和重点
规则:
- 一个对象的编译类型与运行类型可以不一致
- 编译类型在定义对象时,就确定了,不能改变,而运行类型是可以变化的
- 编译类型看定义对象=号的左边, 运行类型看=号的右边
代码演示
class Animal {public void eat(){System.out.println("动物吃饭");}
}class Cat extends Animal {@Overridepublic void eat() {System.out.println("猫吃鱼");}
}public class Test1Polymorphic {/*多态的前提:1. 要有(继承 \ 实现)关系2. 要有方法重写3. 要有父类引用, 指向子类对象*/public static void main(String[] args) {// 当前事物, 是一只猫Cat c = new Cat();// 当前事物, 是一只动物Animal a = new Cat();a.eat();}
}
多态中的成员访问特点
成员访问特点
- 成员变量 :编译看父类,运行看父类
- 成员方法 :编译看父类,运行看子类
代码演示
class Fu{int num=10;public void method(){System.out.println("Fu..method")}
}class Zi extends Fu{int num=20;public void method(){System.out.println("Zi...method")}
}public class Test{public static void main(String[] args){Fu f=new Zi();System.out.println(f.num);f.method();}
}
//输出: 10 Zi..method
多态的好处和弊端
好处
提高程序的扩展性,定义方法时候,使用父类型作为参数,在使用的时候,使用具体的子类型参与操作
弊端
不能使用子类的特有成员
多态中的转型
向上转型
父类的引用指向子类对象就是向上转型
特点
- 编译类型看左边,运行类型看右边
- 可以调用父类的所有成员(须遵守访问权限)
- 不能调用子类的特有成员
- 运行效果看子类的具体实现
向下转型
一个已经向上转型的子类对象, 将父类引用转为子类引用
格式: 子类型 对象名 = (子类型) 父类的引用;
特点
- 只能强制转换父类的引用,不能强制转换父类的对象
- 要求父类的引用必须指向的是目标类型的对象
- 当向下转型后,可以调用子类类型中所有的成员
代码演示
class Fu {public void show(){System.out.println("Fu..show...");}
}class Zi extends Fu {@Overridepublic void show() {System.out.println("Zi..show...");}public void method(){System.out.println("我是子类特有的方法, method");}
}public class Test3Polymorpic {public static void main(String[] args) {// 1. 向上转型 : 父类引用指向子类对象Fu f = new Zi();f.show();// 多态的弊端: 不能调用子类特有的成员// f.method();// A: 直接创建子类对象// B: 向下转型// 2. 向下转型 : 从父类类型, 转换回子类类型Zi z = (Zi) f;z.method();}
}
多态中转型存在的风险和解决方案
风险
如果被转的引用类型变量,对应的实际类型和目标类型不是同一种类型,那么在转换的时候就会出现ClassCastException
解决方案
关键字
instanceof
使用格式
变量名 instanceof 类型
通俗的理解: 判断关键字左边的变量,是否是右边的类型,返回Boolean类型结果
动态绑定
- 当调用方法时,该方法会和该对象的运行内存绑定
- 当调用对象属性时,没有动态绑定机制,即哪里声明,哪里使用
应用
多态数组
多态数组:数组的定义类型为父类类型,里面保存的实际元素为子类类型
代码演示
public class person{private String name;public Person(String name){this.name=name;}//get和set方法public String getName(){return name;}public Void setName(String name){this.name=name;}//mission()方法public String mission(){return name + "\t" + "做人要厚道";}
}public class Student extends Person {private double score;public Student(String name, double score) {super(name);this.score = score;}public double getScore() {return score;}public void setScore(double score) {this.score = score;}//重写父类的say方法@Overridepublic String mission() { return super.mission() + " score =" + score + " 要好好学习!";}
}public class Teacher extends Person {private double salary;public Teacher(String name, double salary) {super(name);this.salary = salary;}public double getSalary() {return salary;}public void setSalary(double salary) {this.salary = salary;}//重写父类的 mission 方法@Overridepublic String mission() { return super.mission() + " salary =" + salary + " 要好好教书!";}
}
//开始演示多态数组
//创建一个Person对象
//创建一个Student对象
//创建一个Teacher对象
//统一放在数组里 并调用每个对象的missio()方法public class Arr{public static void main(String [] args){Person[] persons = new Person[3];Persons[0] = new Person("小白");Persons[1] = new Student("小王",12);Persons[2] = new Teacher("老黑",1000);//循环遍历多态数组for(int i; i < Persons.length; i++){//此位置涉及动态绑定机制//Persons[i]编译类型是Person , 运行类型根据实际情况由JVM判断System.out.prinln(Persons[i].mission())}}
}//运行结果
小白 做人要厚道!
小王 做人要厚道! score = 12 要好好学习!
老黑 做人要厚道! salary = 1000 要好好教书!
多态参数
方法定义的形参类型为父类类型,实参类型允许为子类类型
代码演示
//演示多态参数
public class PolyParameter { public static void main(String[] args) {Student s1 = new Student("小蓝同学");Teacher t1 = new Teacher("小绿老师");//需先 new 一个当前类的实例化,才能调用 test 方法PolyParameter polyParameter = new PolyParameter();//实参是子类polyParameter.test(s1);polyParameter.test(t1); }//定义方法test,形参为 Person 类型(形参是父类)//功能:调用学生的study或教师的teach方法public void test(Person p) {if (p instanceof Student){((Student) p).study(); //向下转型}else if (p instanceof Teacher){((Teacher) p).teach(); //向下转型} }
}//父类
class Person {private String name;//有参构造public Person(String name) {this.name = name;}// getter 和 setterpublic String getName() {return name;}public void setName(String name) {this.name = name;}
}//子类
class Student extends Person {public Student(String name) {super(name);}// study() 方法public void study() { System.out.println(super.getName() + "\t" + "正在好好学习");}
}class Teacher extends Person {public Teacher(String name) {super(name);}// teach() 方法public void teach() { System.out.println(super.getName() + "\t" + "正在好好教书");}
}//运行结果
小蓝同学 正在好好学习
小绿老师 正在好好教书