java面向对象(3)(多态)
文章内容发布于 5 天前;最后修改于 5 日前。其中的信息可能发生变化或产生更改,敬请留意。

继承是多态的前提条件。

多态

什么是多态:同类型对象表现出的不同形态,对象的多种形态。

多态的表现形式<父类类型> <对象名称> = <子类对象>

多态的前提

  1. 与继承(面向对象)或者实现(接口)有关系;
  2. 存在父类引用指向子类对象;
  3. 有方法重写。

多态的举例

public class PolymorphismDemo {
    public static void main(String[] args) {
        Student s1 = new Student();
        s1.setName("John");
        s1.setAge(23);
        Teacher t1 = new Teacher();
        t1.setName("Jack");
        t1.setAge(88);
        Creation(s1);
        Creation(t1);
    }
    public static void Creation(Person p) {
        p.show();
    }
}
class Person {
    private String name;
    private int age;
    public Person() {
        this("Default", 0);
    }
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public void show() {
        System.out.println("Person Class" + this.name + this.age);
    }
}
class Student extends Person {
    @Override
    public void show() {
        System.out.println("Student Class" + super.getName() + super.getAge());
    }
}
class Teacher extends Person {
    @Override
    public void show() {
        System.out.println("Teacher Class" + super.getName() + super.getAge());
    }
}

多态的好处

使用基类类型作为参数,可以接收所有派生类的对象,体现其扩展性和便利性。

多态调用成员的特点

多态调用成员变量

编译看左边,运行也看左边

public class PolymorphismDemo {
    public static void main(String[] args) {
        Animal a = new Cat();
        System.out.println(a.animalType);
    }
}
class Animal {
    public String animalType = "Default Animal";
}
class Dog extends Animal {
    public String animalType = "Dog";
}
class Cat extends Animal {
    public String animalType = "Cat";
}

多态调用成员变量,编译看左边,运行也看左边

编译:在System.out.println(a.animalType);这句代码中,使用javac编译代码的时候,会核查左边的父类有没有这个成员变量:如果有,则编译成功;反之,编译失败。

运行:java在运行代码的时候,实际获取的值是左边基类中成员变量的值。

作为举例,我们将上述代码中,基类中定义animalType变量的语句删除,如下图:

多态调用成员方法

编译看左边,运行看右边

public class PolymorphismDemo {
    public static void main(String[] args) {
        Animal a = new Cat();
        a.showMyAnimal();
    }
}
class Animal {
    private String animalType = "Default Animal";
    public void showMyAnimal() {
        System.out.println("Animal Class -> Animal's type is " + this.animalType);
    }
}
class Dog extends Animal {
    private String animalType = "Dog";
    @Override
    public void showMyAnimal() {
        System.out.println("Dog Class -> Animal's type is " + this.animalType);
    }
}
class Cat extends Animal {
    private String animalType = "Cat";
    @Override
    public void showMyAnimal() {
        System.out.println("Cat Class -> Animal's type is " + this.animalType);
    }
}

多态调用成员方法:编译看左边,运行看右边

编译:在a.showMyAnimal();这句代码中,使用javac编译代码的时候,会核查左边的父类有没有这个成员方法:如果有,则编译成功;反之,编译失败。

运行:java在运行的时候,实际上运行的是派生类中重写的同名成员方法。

作为举例,我们将上述代码中,基类中定义showMyAnimal()变量的语句删除,如下图:

理解

无论是多态中调用成员变量或者成员方法,都是基类的对象作为调用的主体,所以无论是多态调用成员变量还是成员方法,都需要基类中存在对应的变量或者方法。

而多态调用成员变量的时候,派生类的构造时,会将基类的成员对象也继承下来(不管基类的对象是publicprotected或是private,访问权限影响的是代码层面的直接访问,不影响内存分配),多态调用成员变量时,访问的一直是基类中定义的变量。

而多态调用成员方法的时候,如果派生类对方法进行重写,则在虚方法表中对应的方法引用会被替换为派生类的方法实现。所以多态在调用成员方法的时候,调用的是派生类中重写的方法,如果派生类未重写,则调用基类的方法(实际上是调用派生类虚方法表中记录的成员方法)。

成员变量没有多态性,而成员方法有多态性。

多态的优势和弊端

优势

结论

  1. 在多态的形式下,右边的对象可以实现解耦合,便于扩展和维护。
  2. 定义方法的时候,使用父类类型作为参数,则可以接收所有子类对象,体现多态的扩展性和便利性。

理解

我们可以这样理解:

public class PolymorphismDemo {
    public static void main(String[] args) {
        Animal a = new Cat();
        a.play();
    }
}
class Animal {
    public void play() {
        System.out.println("Animal Class -> Animal is playing.");
    }
}
class Dog extends Animal {
    @Override
    public void play() {
        System.out.println("Dog Class -> Dog is fetching a stick!");
    }
}
class Cat extends Animal {
    @Override
    public void play() {
        System.out.println("Cat Class -> Cat is chasing a ball of yarn!");
    }
}

对于第一点,在多态的形式下,右边的对象可以实现解耦合,便于扩展和维护:

假设我们代码如上,在这里面,我们让Animal类的对象a在play(调用play()方法),而这个a实际是Cat类型,所以调用成员方法的时候,编译看左边,运行看右边,实际上运行的是Cat类中的成员方法play()

如果我现在不希望猫在玩,而是狗在玩,只需要将Animal a = new Cat();修改为Animal a = new Dog();,即可完成修改。

如果不使用多态,则Cat c = new Cat();Dog d = new Dog();,如果需要修改,则需要重写修改大量的具体实现代码,导致扩展性极低,系统耦合度极高,增加运维难度。

对于第二点,定义方法的时候,使用父类类型作为参数,则可以接收所有子类对象,体现多态的扩展性和便利性:

在示例代码块中Animal a = new Cat();,左边是抽象(Animal),右边是具体实现(Cat)。

如果我们需要新增更多的动物,在不使用多态的情况下,需要添加更多的类来接收动物,并且需要修改所有的抽象类中的逻辑以适应新增的动物;而使用父类作为参数类型,也就是使用多态的情况下,需要添加更多动物,不需要修改现有的方法定义,只需创建新的子类即可。

弊端

结论

  1. 在多态的形式下,无法调用子类独有方法
  2. 定义方法的时候,使用父类类型作为参数,则可以接收所有子类对象,体现多态的扩展性和便利性。

理解

我们可以这样理解:

public class PolymorphismDemo {
    public static void main(String[] args) {
        Animal a = new Cat();
        // a.catCatchMouse();
        Cat c = (Cat) a;
        c.catCatchMouse();
    }
}
class Animal {
    public void eat() {
        System.out.println("Animal Class -> Animal is eating.");
    }
}
class Dog extends Animal {
    @Override
    public void eat() {
        System.out.println("Dog Class -> Dog is eating meat.");
    }
    public void dogDuardHouse() {
        System.out.println("Dog Class -> Dog is guarding the house!");
    }
}
class Cat extends Animal {
    @Override
    public void eat() {
        System.out.println("Cat Class -> Cat is eating fish.");
    }
    public void catCatchMouse() {
        System.out.println("Cat Class -> Cat caught a mouse!");
    }
}

在多态的形式下,无法调用子类独有方法:

因为调用成员方法的时候,编译时会判断父类是否有同名方法。而子类独有方法是不存在于父类的,所以编译会出错。在如上代码块中a.catCatchMouse();语句被注释了,因为如果编译这一句语句,则会判断父类是否有catCatchMouse()方法,而这个方法是子类独有的,就此产生报错。

如果希望可以调用子类独有的方法,可以考虑将变量强制类型转换为子类,如上面代码块中的Cat c = (Cat) a; c.catCatchMouse();,这样c就是Cat的类的对象,则可以调用独有的方法。

但是在进行强制类型转换的时候需要注意,不可以随意转换对象的类型,比如不能通过Dog类型的Animal变量强制转换为Cat类型,这样在编译的时候会直接报错。

如何避免错误转换:可以使用instanceof来判断,其语法是:<对象> instanceof <类名>,返回为布尔值。

public class PolymorphismDemo {
    public static void main(String[] args) {
        Animal a = new Dog();
        if (a instanceof Dog) {
            Dog d = (Dog) a;
        } else if (a instanceof Cat) {
            Cat c = (Cat) a;
        }  else {
            Animal newAnimal = a;
        }
    }
}
class Animal {}
class Dog extends Animal {}
class Cat extends Animal {}

JDK14+新特性

语法:<对象> instanceof <类名> <新变量名>

public class PolymorphismDemo {
    public static void main(String[] args) {
        Animal a = new Dog();
        if (a instanceof Dog d) {}
    }
}
class Animal {}
class Dog extends Animal {}
class Cat extends Animal {}

逻辑如下:先判断传入值a是否是Dog类型,如果是,则直接创建Dog类的对象d并直接接收来自a强制类型转换后的结果。如果否,则直接返回false

文章「java面向对象(3)(多态)」,由本站用户「Admin」发布。文章仅代表Admin观点,不代表本站立场。
页面网页地址「https://xiaozhiyuqwq.top/p/2873」。
如您对文章及其附件提出版权主张,或进行引用转载等,请查看我们的【版权声明】
本页面暂时没有评论......

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇