Java(二十八)多态

多态

多态介绍

Java使用多态的原因是因为它可以提高代码的灵活性和可复用性。多态是指一个对象可以具有多种形态,即不同的类或接口类型。在Java中,多态通过继承、接口和重载等机制实现。

3621424d95ab42fd8a40afd9f4ff8afc.png

简单的说就是一个对象有多种形态,具体点说多态就是父类中的属性和方法被子类继承后,可以具有不同的数据类型或不同的行为,使父类中的同一个属性和方法在父类与各个子类具有不同的含义。

如下图:子类都继承了父类,但同一个eat方法在不同父类子类中表现不同行为就是多态。

fcde395c088942629557b608110d4bd0.png

再比如打印机分为黑白打印机和彩色打印机,在黑白打印机情况下打出来为黑白,在彩色打印机情况下打印出来为彩色。子类(黑白打印机和彩色打印机)都继承了父类(打印机),但同一个打印方法在不同父类子类中表现不同行为(黑白,彩色)就是多态。

cfcba0d7ce1a433097078f888be7f8fc.png

 多态性是对象多种表现形式的体现。

现实中,比如我们按下 F1 键这个动作:

如果当前在 Flash 界面下弹出的就是 的帮助文档;如果当前在 Word 下弹出的就是 Word 帮助;在 Windows 下弹出的就是 Windows 帮助和支持。同一个事件发生在不同的对象上会产生不同的结果

 

多态的条件

三大条件:

  1. 继承:必须存在继承; extends
  2. 向上转型:通过父类的引用调用子类的重写的方法;
  3.  重写(override):又称覆盖,在子类中创建一个与父类具有相同的返回值类型、方法名、参数列表的方法,以实现与父类不同的行为。

多态的格式

父类类型  变量名 = new 子类类型();

然后通过 变量名.方法名()调用在子类中重写的方法

cc341303de5e4c19bd40320a15a205a3.png

 

多态的例子 

public class Animal {
    public void eat(){
        System.out.println("Animal eat");
    }
}

public class Cat extends Animal{
    public void eat(){
        System.out.println("cat eat");
    }
}

public class Dog extends Animal{
    public void eat(){
        System.out.println("dog eat");
    }
    public static void main(String[] args) {
        Animal an = new Dog();
        Animal an1 = new Cat();
        an.eat();
        an1.eat();
    }
}

 

 

举个栗子,一只鸡可以做成白切鸡、豉油鸡、吊烧鸡、茶油鸡、盐焗鸡、葱油鸡、手撕鸡、清蒸鸡、叫花鸡、啤酒鸡、口水鸡、香菇滑鸡、盐水鸡、啫啫滑鸡、鸡公煲等等。

class Chicken{

public void live(){

System.out.println("这是一只鸡");

} }

重写live方法,建立白切鸡类

class BaiqieChicken extends Chicken{

public void live(){

 System.out.println("这是一只会被做成白切鸡的鸡"); } }

main方法里调用

Chicken c = new BaiqieChicken(); c.live();

class JiaoHuaChicken extends Chicken{

public void live(){

System.out.println("这是一只会被做成叫花鸡的鸡"); } }

Chicken c = new JiaoHuaChicken (); c.live();

练习打印机类PrintMachine  彩色打印机类ColorPrint,黑白打印机类HbPrint,都有print方法。Test实现多态

 

转型

将一个类型转换成另一个类型的过程被称为类型转换。 我们所说的对象类型转换,一般是指两个存在继承关系的对象,而不是任意类型的对象。如果两个类型之间没有继承关系,就不允许进行类型转换,否则会抛出强制类型转换异常(java.lang.ClassCastException)。
Java语言允许某个类型的引用变量引用子类的实例,而且可以对这个引用变量进行类型转换。Java中引用类型之间的类型转换(前提是两个类是直接或间接的父子关系)主要有两种,分别是向上转型(upcasting)和向下转型(downcasting) 。

我们先来看下面这张图:

dbb3661ef75f4cb2ad08d206f380765d.png

猫、狗、牛、羊都是动物,所以”动物“是父类,猫狗牛羊是具体的子类。我们可以说猫是动物,狗是动物,牛是动物,羊是动物,这个结论肯定没错!但如果我们说,动物是猫,动物是狗,动物是牛,动物是羊,这个结论一定正确吗?那可就不一定了。子类肯定符合父类类型,但反之,父类不一定符合子类类型

接下来分别对向上转型和向下转型进行讲解。

 向上转型

实际上就是创建一个子类对象,将其当作父类对象来使用。所谓的向上转型,就是父类引用指向子类的对象,也就是把子类对象直接赋给父类引用变量,此时不用强制转换。比如我们说猫是动物,狗是动物,牛是动物,羊是动物,这就是把子类当成父类来用。父类是子类的上级,我们直接把子类向上提拔转型了。

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

 

向上转型具有如下特点:

  • 编译类型取决于=号左边,运行类型取决于=号右边;
  • 子类可以调用父类的所有成员,但需遵守访问权限;
  • 父类不能调用子类的特有成员;
  • 最终的运行效果取决于子类的具体实现。

使用场景:当不需要面对子类类型时,通过提高扩展性,或者使用父类的功能就能完成相应的操作

2296d9bdde0347aea9b523f3c3fb86e1.png 

Animal cat = new Cat();

//向上转型,将Cat类型转换为Animal类型,小范围向大范围的转换

8752483966e94b318116bf75311d8bd1.png

代码

class Aminal {
    public void display() {
        System.out.println("Animal");
    }
}
class Cat extends Aminal {
    public void display() {
        System.out.println("Cat");
    }
}
class Dog extends Aminal {
public void display() {
        System.out.println("Dog");
    }
 
}
 
public class Main{
    public static void main(String[] args) {
        Aminal aminal1 = new Aminal();
        Aminal aminal2 = new Cat();
        Aminal aminal3 = new Dog();
 
        aminal1.display();
        aminal2.display();
        aminal3.display();
    }
}

优点:让代码实现更简单灵活

缺点:不能调用到子类特有的方法

 例如

class Animal {
    public void display() {
        System.out.println("Animal");
    }
}
 
class Dog extends Animal {
    public void display() {
        System.out.println("dog");
    }
 
    public void eat() {
        System.out.println("吃骨头");
    }
}
 
public class Main {
    public static void main(String[] args) {
        Animal animal = new Dog();
 
        animal.display();
        animal.eat(); //会报错
    }
}

 

向下转型

向下转型:在 Java 中,向下转型(Downcasting)是与向上转型相对的概念,向上转型是将子类对象的引用赋值给父类类型的变量,而向下转型则是将父类类型的引用强制转换为子类类型的引用。通俗来讲就是将一个子类对象向上转型之后可以当成父类对象使用,若需要调用子类特有的方法,则需要将父类对象再还原为子类对象。这就称作向下转型。
使用格式:子类类型 变量名=(子类类型) 父类类型的变量;

cc9db5195f98480c9c3247a59764c3ab.png

90e4753ad11f4f179381f0ca31c7941d.png

适用场景:当要使用子类特有功能时。

当子类对象向上转型后,将无法调用子类中的方法,如果我们想调用子类特有的方法,我们就可以使用向下转型,将父类引用还原成子类对象即可。

class Animal {
    public void display() {
        System.out.println("Animal");
    }
}
 
class Dog extends Animal {
    public void display() {
        System.out.println("dog");
    }
 
    public void eat() {
        System.out.println("吃骨头");
    }
}
 
public class Main{
    public static void main(String[] args) {
        //向上转型
        Animal animal = new Dog();
        animal.display();
        
        //向下转型
        //Animal类中原本没有 eat方法,在向下转型之前如果调用eat方法会报错
        //向下转型为子类Dog类后,就可以调用子类中特有的方法,而不会报错
        animal = (Dog)animal;
        ((Dog) animal).eat();
    }
}

向下转型有的时候不太安全

例如:一个狗类对象向上转型转换为动物类,在向下转型的时候不一定转换为狗类,可能转换为猫类等,所以当我们向下转型的时候要加上强制转换符。

有的时候也会造成抛出异常,所以Java中引入了instanceof,如果结果为true,则可以安全转换。

Java中为了提高向下转型的安全性,引入了 instanceof ,如果该表达式为true,则可以安全转换

class Animal {
    public void display() {
        System.out.println("Animal");
    }
}
 
class Dog extends Animal {
    public void display() {
        System.out.println("dog");
    }
 
    public void eat() {
        System.out.println("吃骨头");
    }
}
public class Main {
    public static void main(String[] args) {
        //向上转型
        Animal animal = new Dog();
        
        //判断instanceof 是否为 true
        if(animal instanceof Dog) {
            //向下转型
            animal = (Dog)animal;
            ((Dog) animal).eat();
        } else {
            System.out.println("Animal无法向下转型为Dog");
        }
    }
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

薛定谔的猫1981

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值