多态的介绍

多态的介绍

多态

什么是多态

同一个对象(父类引用),在不同时刻(父类引用指向不同子类对象时),表现出来的不同形态(子类中重写的方法)

// Person是父类,Student和Teacher是子类 
Person a1 = new Student(); // new Student();是创建了子类的对象
Person a2 = new Teacher();
a1.eat(); // Student类中的方法
a2.eat();

多态的前提

1.要有继承或实现关系

2.要有方法的重写

3.要有父类引用指向子类对象

/*
        1.要有继承或实现关系
        2.要有方法的重写
        3.要有父类引用指向子类对象
*/
public class Test {
    public static void main(String[] args) {
        // 父类引用指向了子类对象
        Fu fu = new Zi1();
        fu.speak();
        // 父类引用指向了子类对象
        Fu fu1 = new Zi2();
        fu1.speak();
    }


}
// 父类
class Fu {
    public void speak(){
        System.out.println("乖儿子,叫爸爸!");
    }
}

// 子类1继承了父类Fu
class Zi1 extends Fu{
    @Override
    public void speak() {
        System.out.println("爸爸,我是儿子");
    }
}
// 子类2 继承了父类Fu
class Zi2 extends Fu {
    @Override
    public void speak() {
        System.out.println("爸爸,我是女儿");
    }
}

电子产品可以玩游戏,手机和个人电脑都是电子产品.(当然,我知道并不是所有的电子产品都能玩游戏,这只是个小例子,不要在意这些)

我们分析下这个案例

手机和个人电脑都是电子产品,那么电子产品可以作为父类,手机和个人电脑可以作为子类,玩游戏是手机和个人电脑都具有的功能,但是玩游戏的类型又不同,所以可以把玩游戏这个功能作为父类的抽象方法

/*
        1.要有继承或实现关系
        2.要有方法的重写
        3.要有父类引用指向子类对象
*/
public class Test {
    public static void main(String[] args) {
        // 父类的引用指向子类Phone的对象;
        // new Phone();创建了子类Phone的对象
        Electronics electronics = new Phone();
        // 对子类方法的调用
        electronics.playGames();
        // 父类的引用指向了子类 NotebookComputer的对象
        // new NotebookComputer();创建了子类NotebookComputer的对象
        Electronics electronics1 = new NotebookComputer();
        // 对子类方法的调用
        electronics1.playGames();
    }
}
// 抽象类
abstract class Electronics {
    // 抽象方法
    public abstract void playGames();
}

class Phone extends Electronics{
    // 对父类中的方法进行重写
    @Override
    public void playGames() {
        System.out.println("玩王者荣耀");
    }
}


class NotebookComputer extends Electronics{
    // 对父类中的方法进行重写
    @Override
    public void playGames() {
        System.out.println("打传奇");
    }
}

多态中的成员访问特点

  • 构造方法
    • 同继承一样,子类会通过super访问父类的构造方法
  • 成员变量
    • 编译看左边(父类),运行看左边(父类)
  • 成员方法
    • 编译看父类(左边),运行看右边(子类)
/*
       当父类的引用指向子类的对象时候
                以本页中的代码为例子
                成员变量:编译时候看左边,运行时看左边
                意思是:编译的时候,如果fu类中没有成员变量a的时候,该程序就会报错,运行的时候结果是跟随等号的左边
                成员方法:编译时看左边,运行时候看右边
                意思是:编译的时候,左边如果没有show方法,编译会报错,运行的结果是跟随等号的右边
*/
public class Test {
    public static void main(String[] args) {
        // 父类的引用指向子类的对象
        Fu fu = new Zi();
        // 调用成员变量给b赋值并打印输出
        int b = fu.a;  
        System.out.println(b);
        // 调用成员方法
        fu.show();
    }
}
// 父类
class Fu{
    // 成员变量
    int a = 10;
    // 成员方法
    public void show(){
        System.out.println("我是爸爸");
    }
}
// Zi类继承Fu类
class Zi extends Fu{
    // 子类中的成员变量
    int a = 20;
    // 子类中的show方法
    public void show(){
        System.out.println("好吧,我是儿子");
    }
}

多态的好处和弊端

好处

提高程序的扩展性

定义方法时候,使用父类类型作为参数,该方法就可以接收父类的任意子类对象(实现多态的一种方式)

弊端

不能使用子类的特有功能,(多态中成员方法的特点:编译时候看左边(父类),父类没有的方法子类中不能使用,运行时看右边(子类))

多态的应用场景之一

父类作为方法参数

public class Polymorphic {
    //定义方法时候,使用父类类型作为参数,该方法就可以接收父类的任意子类对象(实现多态的一种方式)
    public static void main(String[] args) {
        // 多态实现,接收父类的任意子类对象
        // 无论是接收Cat或者是Dog都不会报错
        useAnimal(new Cat());
        useAnimal(new Dog());
    }
    // 定义一个Animal类型的方法,以父类类型作为参数
    // 该方法可以接收父类的任意子类对象
    public static void useAnimal(Animal animal) {
        // 上面这行代码的含义相当于 Animal animal = new Cat(); 或 Animal animal = new Dog();

        //调用子类中共有的方法,不能调用每个子类的特有的方法,不然会报错
        animal.eat();

        //animal.watchHome();  // 去掉注释后,这行代码会报错,因为不能使用子类特有的方法(功能)
        //animal.catchMouse();// 去掉注释后,这行代码会报错,因为不能使用子类特有的方法(功能)
    }
}

//父类,抽象类,关键字abstract
abstract class Animal {
    // 父类的抽象方法,子类需要重写的方法
    public abstract void eat();
}

// 继承于父类Animal的Cat类
class Cat extends Animal {
    // 重写父类的eat方法
    @Override
    public void eat() {
        System.out.println("猫咪吃肉");
    }

    // 独属于Cat类的方法
    public void catchMouse() {
        System.out.println("小猫会抓老鼠");
    }
}

// 继承于父类Animal的Dog类
class Dog extends Animal {
    // 重写父类的eat方法
    @Override
    public void eat() {
        System.out.println("狗狗吃肉");
    }

    // 独属于Dog类的方法
    public void watchHome() {
        System.out.println("狗狗在看家");
    }
}

多态中的转型

  • 向上转型

    父类引用指向子类对象就是向上转型

    int a = 10;
    double b = a;
    
  • 向下转型

    父类引用转换为子类对象

    格式: 子类型 对象名 = (子类型) 父类引用;

    String b = "100.0";
    int a = (int)b;
    

    代码演示:

    public class Fu_And_Zi {
        public static void main(String[] args) {
        // 向上转型:父类引用指向子类对象
            Fu fu = new Zi();
            fu.show();
            //fu.proud();  //多态的弊端,不能调用子类的成员
    
            // 直接创建子类对象,向下转型
            Zi zi = (Zi) fu; // 将Fu类 类型的对象,强转为Zi类 类型的对象
            zi.proud(); // 转换成功后,就能调用子类特有的方法
        }
    }
    // 创建一个Fu类
    class Fu{
        // Fu类的show方法
        public void show(){
            System.out.println("i have a son");
        }
    }
    class Zi extends Fu{
        // Zi类重写Fu类的show方法
        @Override
        public void show() {
            System.out.println("i have a dad");
        }
        // Zi类特有的方法
        public void proud(){
            System.out.println("This is my father");
        }
    }
    

多态中转型存在的风险和解决方案(应用)

风险

如果被转的引用类型变量,对应的实际类型和目标类型不是同一种类型,那么在转换的时候就会出现ClassCastException

解决方案

  • 关键字

    instanceof

  • 使用格式

    ​ 变量名 instanceof 类型

    通俗的理解:判断关键字左边的变量,是否是右边的类型,返回boolean类型结果

  • 应用场景(拓展):可以用手机号或者QQ号进行登录

    代码演示

    public class AnimalsCode {
        //定义方法时候,使用父类类型作为参数,该方法就可以接收父类的任意子类对象(实现多态的一种方式)
        public static void main(String[] args) {
            // 多态实现,接收父类的任意子类对象
            // 无论是接收Cat或者是Dog都不会报错
            useAnimal(new Cat());
            useAnimal(new Dog());
        }
        // 定义一个Animal类型的方法,以父类类型作为参数
        // 该方法可以接收父类的任意子类对象
        public static Animal useAnimal(Animal animal) {
            // 上面这行代码的含义相当于 Animal animal = new Cat(); 或 Animal animal = new Dog();
    
            //调用子类中共有的方法,不能调用每个子类的特有的方法,不然会报错
            animal.eat();
    
            //animal.watchHome();  // 去掉注释后,这行代码会报错,因为不能使用子类特有的方法(功能)
            //animal.catchMouse();// 去掉注释后,这行代码会报错,因为不能使用子类特有的方法(功能)
    
            // 判断animal记录的对象是否为Dog类型,如果是,执行if语句中的内容
            // instanceof判断两个对象是否为同一个类型,返回值是boolean类型
            if(animal instanceof Dog){
                // 将Animal类型的对象animal转换成Dog类型对象,调用Dog中特有的方法
                Dog dog = (Dog) animal;
                dog.watchHome();
            }
    
            // 返回一个对象
            return animal;
        }
    }
    
    //父类,抽象类,关键字abstract
    abstract class Animal {
        // 父类的抽象方法,子类需要重写的方法
        public abstract void eat();
    }
    
    // 继承于父类Animal的Cat类
    class Cat extends Animal {
        // 重写父类的eat方法
        @Override
        public void eat() {
            System.out.println("猫咪吃肉");
        }
    
        // 独属于Cat类的方法
        public void catchMouse() {
            System.out.println("小猫会抓老鼠");
        }
    }
    
    // 继承于父类Animal的Dog类
    class Dog extends Animal {
        // 重写父类的eat方法
        @Override
        public void eat() {
            System.out.println("狗狗吃肉");
        }
    
        // 独属于Dog类的方法
        public void watchHome() {
            System.out.println("狗狗在看家");
        }
    }
    

小结

什么是多态

同一个对象(父类对象).在不同时刻表现出来的不同形态

多态的前提

  • 要有继承或实现关系
  • 要有方法的重写
  • 要有父类引用指向子类的对象

多态的好处和弊端

  • 好处

提高程序的拓展性,定义方法的时候,使用父类类型作为参数,该方法就可以接受父类的任意子类对象

  • 弊端

不能使用子类的特有功能

多态中转型

  • 风险

如果被转的引用类型变量,对应的实际类型和目标类型不是同一种类型,那么在转换的时候就会出现ClassCastException\

  • 解决方案

    • 关键字

      instanceof

    • 使用格式

      类型1 instanceof 类型2

      通俗的理解:判断关键字左边的类型,是否是右边的类型,返回boolean类型结果

多态常见的两种应用场景

使用父类作为方法形参,实现多态

使用父类作为返回值,实现多态

// 使用父类作为返回值,实现多态(第二种多态的实现方式)

// 创建一个Fu类
class Fu{
    // Fu类的show方法
    public void show(){
        System.out.println("i have a son");
    }
}
class Zi extends Fu{
    // Zi类重写Fu类的show方法
    @Override
    public void show() {
        System.out.println("i have a dad");
    }
    // Zi类特有的方法
    public void proud(){
        System.out.println("This is my father");
    }
}
// 创建一个工厂类,使用父类类型作为返回值类型
class PersonFoctory{
    public static  Fu getFu(){
        return new Zi();
    }
}
public class Fu_And_Zi {
    public static void main(String[] args) {
        // 多态的实现
        // 通过工厂类,类获取对象
        Fu fu = PersonFoctory.getFu();
        fu.show(); // 打印出的是子类的show方法,enmmm,我试过了,是真的!
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值