【JavaSE】多态的基本使用

简介: 【JavaSE】多态的基本使用

1. 先看一个问题

在这里插入图片描述

  • 使用传统的方法来解决(private 属性)
public class Animal {
    private String name;

    public Animal(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
public class Dog extends Animal{
    public Dog(String name) {
        super(name);
    }
}
public class Cat extends Animal{
    public Cat(String name) {
        super(name);
    }
}
public class Food {
    private String name;

    public Food(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
public class Bone extends Food{
    public Bone(String name) {
        super(name);
    }
}
public class Fish extends Food{
    public Fish(String name) {
        super(name);
    }
}
public class Master {
    private String name;

    public Master(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    //主人给小狗骨头
    public void feed(Dog dog,Bone bone){
        System.out.println("主人" + name + " 给 " + dog.getName() + " 吃" + bone.getName());
    }
    //主人给小猫吃黄花鱼
    public void feed(Cat cat,Fish fish){
        System.out.println("主人" + name + " 给 " + cat.getName() + " 吃" + fish.getName());
    }

    //如果动物很多,食物很多
    //===> feed 方法很多,不利于管理和维护
    //Pig --> Rice
    //Tiger ---> meat ...
    //...
}
public class Poly01 {
    public static void main(String[] args) {
        Master master = new Master("tom");
        Dog dog = new Dog("旺财");
        Bone bone = new Bone("大骨棒");

        master.feed(dog,bone);

        Cat cat = new Cat("小花猫");
        Fish fish = new Fish("黄花鱼");
        master.feed(cat,fish);
    }
}

在这里插入图片描述

  • 传统的方法带来的问题是什么? 如何解决?

问题是: 代码的复用性不高,而且不利于代码维护
解决方案: 引出多态

2. 多[多种]态[状态]基本介绍

  • 方法或对象具有多种形态。是面向对象的第三大特征,多态是建立在封装和继承基础之上的。

3. 多态的具体体现

1) 方法的多态 PloyMethod.java
重写和重载就体现多态 [案例说明]

public class PloyMethod {
    public static void main(String[] args) {
        //方法重载体现多态
        A a = new A();
        //这里传入不同的参数,就会调用不同sum方法,就体现多态
        System.out.println(a.sum(10, 20));
        System.out.println(a.sum(10, 20, 30));

        //方法重写体现多态
        B b = new B();
        a.say();
        b.say();

    }
}
class B { //父类
    public void say() {
        System.out.println("B say() 方法被调用...");
    }
}
class A extends B {//子类
    public int sum(int n1, int n2){//和下面sum 构成重载
        return n1 + n2;
    }
    public int sum(int n1, int n2, int n3){
        return n1 + n2 + n3;
    }


    public void say() {
        System.out.println("A say() 方法被调用...");
    }
}

在这里插入图片描述

2) 对象的多态
(1)一个对象的编译类型和运行类型可以不一致
(2)编译类型在定义对象时,就确定了,不能改变
(3)运行类型是可以变化的.
(4)编译类型看定义时=号的左边,运行类型看=号的右边

  • 案例:com.xdr630.poly.objpoly: PolyObject.java

Animal animal = new Dog(); 【animal编译类型是Animal,运行类型Dog】
animal = new Cat(); 【animal的运行类型变成了Cat,编译类型仍然是 Animal】

public class Animal {
    public void cry(){
        System.out.println("Animal cry() 动物在叫...");
    }
}
public class Dog extends Animal {
    @Override
    public void cry() {
        System.out.println("Dog cry() 小狗在叫...");

    }
}
public class Cat extends Animal{
    @Override
    public void cry() {
        System.out.println("Cat cry() 小猫在叫... ");
    }
}
public class PolyObject {
    public static void main(String[] args) {
        // 体验对象多态的特点

        //animal 编译类型就是Animal,运行类型 Dog
        Animal animal = new Dog();
        //因为运行时,执行到该行时,animal运行类型是Dog,所以cry就是Dog的cry
        animal.cry();   //小狗在叫...

        //animal 变异类型是 Animal,运行类似 Cat
        animal = new Cat();
        animal.cry();   //小猫在叫...
    }
}

在这里插入图片描述

4. 多态快速入门案例

  • 使用多态的机制来解决主人喂食物的问题
  • Poly01.java
  • 在上面的 Master 类中添加如下,注释前面两个 feed 方法
//使用多态机制,可以统一管理主人喂食的问题
//animal 编译类型是 Animal ,可以指向(接收)Animal子类的对象
//food 编译类型是 Food,可以指向(接收)Food子类的对象
public void feed(Animal animal,Food food){
    System.out.println("主人" + name + " 给 " + animal.getName() + " 吃" + food.getName());
}
  • 运行:

在这里插入图片描述

5. 多态注意事项和细节讨论

com.xdr630.poly_.detail_ 包 : PolyDetail.java

  • 多态的前提是:两个对象(类)存在继承关系

5.1 多态的向上转型

1)本质:父类的引用指向了子类的对象
2)语法:父类类型 引用名 = new 子类类型();
3)特点:编译类型看左边,运行类型看右边。
可以调用父类中的所有成员(需遵守访问权限)
不能调用子类中特有成员;
最终运行效果看子类的具体实现!

public class Animal {
    String name = "动物";
    int age = 10;
    public void sleep(){
        System.out.println("睡");
    }
    public void run(){
        System.out.println("跑");
    }
    public void eat(){
        System.out.println("吃");
    }
    public void show(){
        System.out.println("hello,你好");
    }

}
public class Cat extends Animal {
    public void eat(){//方法重写
        System.out.println("猫吃鱼");
    }
    public void catchMouse(){//Cat特有方法
        System.out.println("猫抓老鼠");
    }
}
public class PolyDetail {
    public static void main(String[] args) {

        //向上转型: 父类的引用指向了子类的对象
        //语法:父类类型引用名 = new 子类类型();
        Animal animal = new Cat();
        Object obj = new Cat();//可以吗? 可以 Object 也是 Cat的父类

        //向上转型调用方法的规则如下:
        //(1)可以调用父类中的所有成员(需遵守访问权限)
        //(2)但是不能调用子类的特有的成员
        //(#)因为在编译阶段,能调用哪些成员,是由编译类型来决定的
        //animal.catchMouse();错误
        //(4)最终运行效果看子类(运行类型)的具体实现, 即调用方法时,按照从子类(运行类型)开始查找方法
        //,然后调用,规则我前面我们讲的方法调用规则一致。
        animal.eat();//猫吃鱼..
        animal.run();//跑
        animal.show();//hello,你好
        animal.sleep();//睡

    }
}

在这里插入图片描述

5.2 多态的向下转型

1)语法:子类类型 引用名= (子类类型) 父类引用;
2)只能强转父类的引用,不能强转父类的对象
3)要求父类的引用必须指向的是当前目标类型的对象
4)当向下转型后,可以调用子类类型中所有的成员

public class PolyDetail {
    public static void main(String[] args) {

        //向上转型: 父类的引用指向了子类的对象
        //语法:父类类型引用名 = new 子类类型();
        Animal animal = new Cat();
        Object obj = new Cat();//可以吗? 可以 Object 也是 Cat的父类

        //向上转型调用方法的规则如下:
        //(1)可以调用父类中的所有成员(需遵守访问权限)
        //(2)但是不能调用子类的特有的成员
        //(#)因为在编译阶段,能调用哪些成员,是由编译类型来决定的
        //animal.catchMouse();错误
        //(4)最终运行效果看子类(运行类型)的具体实现, 即调用方法时,按照从子类(运行类型)开始查找方法
        //,然后调用,规则我前面我们讲的方法调用规则一致。
        animal.eat();//猫吃鱼..
        animal.run();//跑
        animal.show();//hello,你好
        animal.sleep();//睡

        //希望,可以调用Cat的 catchMouse方法
        //多态的向下转型
        //(1)语法:子类类型 引用名 =(子类类型)父类引用;
        //问一个问题? cat 的编译类型 Cat,运行类型是 Cat
        Cat cat = (Cat) animal;
        cat.catchMouse();//猫抓老鼠
        //(2)要求父类的引用必须指向的是当前目标类型的对象
        //Dog dog = (Dog) animal; //可以吗?不可以

    }
}

在这里插入图片描述

  • 属性没有重写之说,属性的值看编译类型 PolyDetail02.java
public class PolyDetail02 {
    public static void main(String[] args) {
        //属性没有重写之说!属性的值看编译类型
        Base base = new Sub();//向上转型
        System.out.println(base.count);// ? 看编译类型 10
        Sub sub = new Sub();
        System.out.println(sub.count);//?  20
    }
}

class Base { //父类
    int count = 10;//属性
}
class Sub extends Base {//子类
    int count = 20;//属性
}

在这里插入图片描述

  • instanceOf 比较操作符,用于判断对象的运行类型是否为 XX 类型或 XX 类型的子类型【举例说明】PolyDetail03.java
public class PolyDetail03 {
    public static void main(String[] args) {
        BB bb = new BB();
        System.out.println(bb instanceof  BB);// true
        System.out.println(bb instanceof  AA);// true

        //aa 编译类型 AA, 运行类型是BB
        //BB是AA子类
        AA aa = new BB();
        System.out.println(aa instanceof AA);
        System.out.println(aa instanceof BB);

        Object obj = new Object();
        System.out.println(obj instanceof AA);//false
        String str = "hello";
        //System.out.println(str instanceof AA);
        System.out.println(str instanceof Object);//true
    }
}

class AA {} //父类
class BB extends AA {}//子类

在这里插入图片描述

6. 练习

  1. 请说出下面的每条语言,哪些是正确的,哪些是错误的,为什么?

在这里插入图片描述

  1. 练习
  • 注意属性看编译类型是哪个,方法看运行类型是哪个。
  • 代码分析:

Base b = s;相当于向上转型,把子类对象赋给父类对象,所以 b==s
b.count = 10; 因为 count 是属性,看编译类型,是Base(父类),所以为10
b.display = 20; 因为 display 是方法,看运行类型,是Sub(子类),所以为2-

public class PolyExercise02 {
    public static void main(String[] args) {
        Sub s = new Sub();
        System.out.println(s.count);//20
        s.display();//20
        Base b = s;
        System.out.println(b == s);//T
        System.out.println(b.count);//10
        b.display();//20
    }
}

class Base {//父类
    int count = 10;

    public void display() {
        System.out.println(this.count);
    }
}

class Sub extends Base {//子类
    int count = 20;

    public void display() {
        System.out.println(this.count);
    }
}

在这里插入图片描述

目录
相关文章
|
Java 编译器
【JAVASE】类与对象 中
【JAVASE】类与对象
|
Java 编译器
【JAVASE】类与对象 下
【JAVASE】类与对象
|
6月前
|
存储 SQL Java
【JavaSE语法】类和对象(二)
本文主要介绍了面向对象的三大特点之一封装,并引入了包的概念;还介绍了static修饰类的成员(变量+方法),最突出的特点就是static修饰的属于类,而不属于某个对象;最后介绍了四种代码块
52 7
|
6月前
|
Java 编译器
JavaSE学习之--继承和多态(一)
JavaSE学习之--继承和多态
62 0
|
6月前
|
Java 编译器
JavaSE学习之--继承和多态(三)
JavaSE学习之--继承和多态(三)
62 0
|
6月前
|
Java
JavaSE学习之--继承和多态(二)
JavaSE学习之--继承和多态(二)
70 0
|
6月前
|
存储 Java 编译器
JavaSE学习之--类和对象(一)
JavaSE学习之--类和对象(一)
51 0
|
存储 Java 编译器
【JavaSE语法】类和对象(一)
【JavaSE语法】类和对象(一)
46 0
|
存储 Java Android开发
【JAVASE】类与对象 上
【JAVASE】类与对象
|
存储 Java Unix
【JavaSE】类和对象解析(1)
【JavaSE】类和对象解析(1)