1、多态的定义
/*
1、多态:同一个对象(事物),在不同时刻体现出来的不同状态。
多态的的使用前提:
1.必须有继承或者实现关系。
2.必须有父类类型的变量引用子类类型的对象。
3.需要存在方法重写。
父 f = new 子();
2、多态中的成员访问特点:
A:成员变量
编译看左边,运行看左边。
B:构造器
创建子类对象的时候,访问父类的构造方法,对父类的数据进行初始化。
C:成员方法
编译看左边,运行看右边。
D:静态方法
编译看左边,运行看左边。
(静态和类相关,算不上重写,所以,访问还是左边的)
由于成员方法存在方法重写,所以它运行看右边。
*/
public class PolymorphicDemo {
public static void main(String[] args) {
// 父类类名 对象名称 = new 子类构造器;
Animal a = new Cat();
a.run(); // 编译看左边,运行看右边。
System.out.println(a.name); // 编译看左边,运行也看左边。
Animal a1 = new Dog();
a1.run(); // 编译看左边,运行看右边。
}
}
class Animal{
public String name = "动物Animal";
public void run(){
System.out.println("动物可以跑~~~~");
}
}
class Cat extends Animal{
public String name = "猫";
@Override
public void run(){
System.out.println("猫跑的贼溜~~~");
}
}
class Dog extends Animal{
@Override
public void run(){
System.out.println("狗跑的贼贼快~~~");
}
}
2、多态的优劣势
/**
多态的优势:
(1)在多态的形势下,右边的对象可以实现组件化解耦思想。
可以随时切换业务逻辑,而不需要更改过多代码,遍历系统的维护,拓展和管理。
(2)实际开发的过程中,父类类型作为方法形式参数,传递子类对象给方法,进行方法的调用
这样该方法可以接收一切子类对象的类型。更能体现出多态的扩展性与便利
多态的劣势:
多态形式下无法调用子类独有的功能,因为编译看左边,左边没有子类独有的功能就直接报错!!。
*/
public class PolymorphicDemo01 {
public static void main(String[] args) {
Animal a = new Cat();
a.run();
// a.catchMouse(); // 多态下无法调用子类独有的功能,编译看左边。
Animal c = new Cat();
start(c);
Animal d = new Dog();
start(d);
}
// 开发一个动物大赛。
public static void start(Animal a){
a.run();
}
}
class Animal{
public void run(){
System.out.println("动物可以跑~~~~");
}
}
class Cat extends Animal{
@Override
public void run(){
System.out.println("猫跑的贼溜~~~");
}
// 独有功能
public void catchMouse(){
System.out.println("猫抓🐀~~~");
}
}
class Dog extends Animal{
@Override
public void run(){
System.out.println("狗跑的贼贼快~~~");
}
}
class Fu{
private void test(){
}
}
class Zi extends Fu{
}
3、自动类型转换
/**
父类类型的范围 > 子类类型的范围
小范围的变量可以自动转换给大范围的变量。
大范围类型的变量必须强制类型转换成小范围的变量。
引用类型的自动类型转换:
子类对象或者子类类型的变量是可以直接自动类型转换给父类类型的变量(自动类型转换,向上转型)
小结:
前提:必须有继承关系才可以类型转换!!
*/
public class PolymorphicDemo {
public static void main(String[] args) {
Animal a = new Cat(); // 子类对象赋值给父类类型的变量 ,自动类型转换。
Cat c = new Cat();
Animal a1 = c ; // 子类类型的变量赋值给父类类型的变量,自动类型转换。
}
}
class Animal{}
class Cat extends Animal{}
4、强制类型转换
/**
父类对象或者父类类型的变量赋值给子类类型的变量必须进行强制类型转换,否则报错!
强制类型转换的格式:
子类名称 对象名称 = (子类名称)父类对象或者父类类型的变量。
类型转换异常的问题:
在编译阶段只要有继承关系的两个类型一定可以进行强制类型转换,编译阶段一定不会报错!!
但是运行阶段可能出现:类型转换异常ClassCastException。
类型转换异常:在运行阶段发现转型以后的类型根本不一致!!!就抛出错误!!
Java建议在进行类型转换之前先进行具体类型的判断,再强制类型转换:
instanceof使用格式: 变量 instanceof 类型
判断变量的真实类型是否是后面的类型或者后面类型的子类类型,是返回true ,不是返回false.
小结:
强制类型可以解决多态的劣势,可以实现访问子类的独有功能。
*/
public class PolymorphicDemo01 {
public static void main(String[] args) {
Animal a = new Cat();
a.run();
// 强制类型转换。
Cat c = (Cat) a;
c.catchMouse();
Animal a1 = new Dog();
// 强制类型转换。
Dog dog = (Dog) a1;
dog.lookDoor();
Animal a2 = new Dog();
// Cat ct = (Cat) a2; // 报错!
// 判断a2的真实类型是否是Dog类型或者其子类类型。
if(a2 instanceof Dog){
Dog d = (Dog) a2;
d.lookDoor();
}else if(a2 instanceof Cat){
Cat ct = (Cat) a2;
ct.catchMouse();
}
}
}
class Animal{
public void run(){
System.out.println("动物可以跑~~~~");
}
}
class Cat extends Animal {
@Override
public void run(){
System.out.println("猫跑的贼溜~~~");
}
// 独有功能
public void catchMouse(){
System.out.println("猫抓🐀~~~");
}
}
class Dog extends Animal {
@Override
public void run(){
System.out.println("狗跑的贼贼快~~~");
}
// 独有功能
public void lookDoor(){
System.out.println("🐕看门~~~");
}
}
5-类型转换异常
/*
ClassCastException:类型转换异常
一般在多态的向下转型中容易出现
*/
class Animal {
public void eat(){}
}
class Dog extends Animal {
public void eat() {}
public void lookDoor() {
}
}
class Cat extends Animal {
public void eat() {
}
public void playGame() {
}
}
class DuoTaiDemo5 {
public static void main(String[] args) {
//内存中的是狗
Animal a = new Dog();
Dog d = (Dog)a;
//内存中是猫
a = new Cat();
Cat c = (Cat)a;
//内存中是猫
Dog dd = (Dog)a; //ClassCastException
}
}
6-多态继承中的内存图解
![](https://img2018.cnblogs.com/blog/1665530/201906/1665530-20190623235528709-429799643.jpg)
7多态中的对象变化内存图解
![](https://img2018.cnblogs.com/blog/1665530/201906/1665530-20190623235557956-2055938171.jpg)