欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

详解Java多态的概念、注意事项和用法

程序员文章站 2024-03-21 20:24:58
...

1 多态概述

概念:

  1. 多态:同一行为,具有多种不同表现形式。
  2. 多态是面向对象的三大特征之一(封装、继承、多态)。
  3. 生活中,比如跑的动作,猫和狗跑起来不同;飞的动作,昆虫和鸟类飞起来不同。可见,同一行为,通过不同的事物,体现出不同的形态。多态描述的就是这种概念。

多态的前提

  1. 继承或实现【二选一】
  2. 方法被重写【不重写,无意义】
  3. 父类引用子类对象【格式体现】

2 多态的格式

格式

父类类型 变量名 = new 子类对象;
变量名.方法名();

Fu f = new Zi();
f.method();

父类类型:子类继承的父类类型,或类实现的父接口类型

使用过程

  1. 使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,编译错误;
  2. 如果有,执行的是子类重写后的方法。

代码示例

// 定义父类
public abstract class Animal {
    public abstract void eat();
}

// 定义子类
class Cat extends Animal {
    public void eat() {
        System.out.println("吃鱼");
    }
}

class Dog extends Animal {
    public void eat() {
        System.out.println("啃骨头");
    }
}

// 定义测试类
public class Test {
    public static void main(String[] args) {
        // 多态形式,创建对象
        Animal a1 = new Cat();
        // 调用的是Cat的eat
        a1.eat();

        // 多态形式,创建对象
        Animal a2 = new Dog();
        // 调用的是Dog的eat
        a2.eat();
    }
}

吃鱼
啃骨头

3 多态的简单应用

实际开发中,父类类型作为方法形式参数,传递子类对象给方法,进行方法调用,更能体现出多态的扩展性与便利。

// 定义父类
	public abstract class Animal {
	    public abstract void eat();
	}

// 定义子类
class Cat extends Animal {
    public void eat() {
        System.out.println("吃鱼");
    }
}

class Dog extends Animal {
    public void eat() {
        System.out.println("啃骨头");
    }
}

// 定义测试类
public class Test {
    public static void main(String[] args) {
        // 多态形式,创建对象
        Cat c = new Cat();
        Dog d = new Dog();

        showAnimalEat(c);
        showAnimalEat(d);
    }

    public static void showAnimalEat(Animal a){
        a.eat();
    }
}

吃鱼
啃骨头

4 多态中的类型转换

多态的转型分为向上转型和向下转型两种。

4.1 向上转型

向上转型:多态本身是子类类型向父类类型向上转换的过程,这个过程是默认的。

当父类引用指向一个子类对象时,便是向上转型。

使用格式:

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

4.2 向下转型

向下转型:父类类型向子类类型向下转换的过程,这个过程是强制的。

一个已经向上转型的子类对象,将父类引用转为子类引用,可以使用强制类型转换的格式,便是向下转型。

格式:

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

4.2.1 为什么向下转型

当使用多态方法调用方法时,首先检查父类中是否有该方法,如果没有则编译错误。也就是说,不能调用子类拥有而父类没有的方法。所以,想要调用子类特有的方法,必须向下转型。

代码示例

// 定义父类
public abstract class Animal {
    public abstract void eat();
}

// 定义子类
class Cat extends Animal {
    public void eat() {
        System.out.println("吃鱼");
    }
    public void catchMouse() {
        System.out.println("抓老鼠");
    }
}

class Dog extends Animal {
    public void eat() {
        System.out.println("啃骨头");
    }
    public void watchHouse() {
        System.out.println("看家");
    }
}

// 定义测试类
public class Test {
    public static void main(String[] args) {
        // 向上转型
        Animal a = new Cat();
        a.eat();

        // 向下转型
        Cat c = (Cat)a;
        c.catchMouse();
    }
}

吃鱼
抓老鼠

4.2.2 向下转型的异常

向下转型的过程有可能会出现以下异常情况

public class Test {
   public static void main(String[] args) {
        // 向上转型
        Animal a = new Cat();// 调用的是Cat的eat
        a.eat();

        // 向下转型
        Dog d = (Dog)a;
        d.watchHouse();//出错
    }
}

程序会报出ClassCastException异常,因为Cat类型向上转型,再向下转型必然也是Cat类型,不能是Dog类型,这两个类型没有任何继承关系,不符合类型转换的定义。

4.2.3 向下转型的异常处理办法

为避免向下转型过程中类型转换异常的出现,使用instanceof关键字给引用变量做类型检验。

格式:

变量名 instanceof 数据类型

1 如果变量属于该数据类型,返回true
2 如果变量不属于该数据类型,返回false

所以,在向下转换前,我们最好先做一个判断,代码如下:

public class Test {
    public static void main(String[] args) {
        // 向上转型
        Animal a = new Cat();
        a.eat();

        // 向下转型
        if (a instanceof Cat) {
            Cat c = (Cat)a;
            c.catchMouse();
        } else if (a instanceof Dog) {
            Dog d = (Dog)a;
            d.watchHouse();
        }
    }
}