3.10、对象多态性

  1. 3.10、对象多态性

3.10、对象多态性

对象的多态性,是整个Java中最重要的一个部分,因为有多态性的存在,才可以让程序变得更加灵活

多态性是面向对象的最后一个特征:

  • 方法重载和方法的覆写实际上就属于多态性的一种体现
  • 真正的多态性还包括了一种称为对象多态性的概念
    • 对象多态性主要指的是:子类和父类对象的相互转换关系
      • 向上转型:父类 父类对象 = 子类实例 –>自动完成
      • 向下转型:子类 子类对象 = (子类)父类实例 –>强制完成

说明:下面的程序只是为了让对象多态性的概念得到体现,本身并不包含任何具体的意义。

class A{
    public void fun1(){
        System.out.println("1、A类-->public void fun1(){}");
    }
    public void fun2(){
        this.fun1();
    }
}
class B extends A{
    public void fun1(){
        System.out.println("2、B类-->public void fun1(){}");
    }
    public void fun3(){
        System.out.println("3、B类-->public void fun3(){}");
    }
}
public class Demo{
    public static void main(String args[]){
        A a = new B();		//发生向上转型关系,子类实例  --> 父类实例
        a.fun2();
    }
}

如果此时希望使用fun3()方法,那么应该发生向下的转型关系

class A{
    public void fun1(){
        System.out.println("1、A类-->public void fun1(){}");
    }
    public void fun2(){
        this.fun1();
    }
}
class B extends A{
    public void fun1(){
        System.out.println("2、B类-->public void fun1(){}");
    }
    public void fun3(){
        System.out.println("3、B类-->public void fun3(){}");
    }
}
public class Demo{
    public static void main(String args[]){
        A a = new B();		//发生向上转型关系,子类实例  --> 父类实例
        B b = (B)a;		//发生向下转型关系,强制完成
        b.fun3();
        b.fun2();
    }
}

再来看以下的程序

class A{
    public void fun1(){
        System.out.println("1、A类-->public void fun1(){}");
    }
    public void fun2(){
        this.fun1();
    }
}
class B extends A{
    public void fun1(){		//将方法覆写了
        System.out.println("2、B类-->public void fun1(){}");
    }
    public void fun3(){
        System.out.println("3、B类-->public void fun3(){}");
    }
}
public class Demo{
    public static void main(String args[]){
        A a = new A();		//发生向上转型关系,子类实例  --> 父类实例
        B b = (B)a;		//发生向下转型关系,强制完成
        b.fun2();
    }
}

程序运行:

Exception in thread "main" java.lang.ClassCastException: A cannot be cast to B
	at Demo00.main(Demo.java:22)

此异常实际上是继NullPointerException之后,第二个最容易出现的异常,表示类转换异常,造成的根本原因是两个没有关系的类进行相互转换操作。

观察对象多态性的作用:

  • 例如:现在要求设计一个方法,那么此方法可以接收A类的所有子类的实例。

如果现在不使用对象多态性的概念完成,则代码如下:

class A{
    public void fun1(){
        System.out.println("1、A类-->public void fun1(){}");
    }
    public void fun2(){
        this.fun1();
    }
}
class B extends A{
    public void fun1(){
        System.out.println("2、B类-->public void fun1(){}");
    }
    public void fun3(){
        System.out.println("3、B类-->public void fun3(){}");
    }
}
class C extends A{
    public void fun1() {
        System.out.println("4、C类-->public void fun1(){}");
    }
    public void fun4(){
        System.out.println("5、C类-->public void fun4(){}");
    }
}


public class Demo00 {
    public static void main(String args[]) {
        fun(new B());
    }
    public static void fun(B b){
        b.fun2();
        b.fun3();
    }
    public static void fun(C c){
        c.fun2();
        c.fun4();
    }
}
  • 以上的方式是通过重载完成,那么使用以上方法完成会存在以下的缺点,如果现在A类的子类有100000个,那么此方法就要重载100000次,而且在每次增加子类的时候都需要修改代码本身。

所以,此时使用对象多态性就可以很好的解决此类问题,因为所有的对象都会发生自动的向上转型操作

class A{
    public void fun1(){
        System.out.println("1、A类-->public void fun1(){}");
    }
    public void fun2(){
        this.fun1();
    }
}
class B extends A{
    public void fun1(){
        System.out.println("2、B类-->public void fun1(){}");
    }
    public void fun3(){
        System.out.println("3、B类-->public void fun3(){}");
    }
}
class C extends A{
    public void fun1() {
        System.out.println("4、C类-->public void fun1(){}");
    }
    public void fun4(){
        System.out.println("5、C类-->public void fun4(){}");
    }
}


public class Demo00 {
    public static void main(String args[]) {
        fun(new B());
        fun(new C());
    }
    public static void fun(A a){
        a.fun2();
    }
}

但是,以上的操作也会存在一个小的问题:

class A{
    public void fun1(){
        System.out.println("1、A类-->public void fun1(){}");
    }
    public void fun2(){
        this.fun1();
    }
}
class B extends A{
    public void fun1(){
        System.out.println("2、B类-->public void fun1(){}");
    }
    public void fun3(){
        System.out.println("3、B类-->public void fun3(){}");
    }
}
class C extends A{
    public void fun1() {
        System.out.println("4、C类-->public void fun1(){}");
    }
    public void fun4(){
        System.out.println("5、C类-->public void fun4(){}");
    }
}


public class Demo00 {
    public static void main(String args[]) {
        fun(new B());
        fun(new C());
    }
    public static void fun(A a){
        a.fun2();
        B b = (B)a;
        b.fun3();
    }
}

以上仍然会出现类型转换异常,那么现在希望如果传入的是B类的实例,则调用fun3(),如果是C类则调用fun4(),那么要完成这样的功能就需要判断传进的对象到底是哪个类的实例了。

在Java中提供了instanceof关键字完成这样的功能。

格式:

对象 instanceof 类  --> 返回boolean类型的数据,值就是true或false
public class Demo00 {
    public static void main(String args[]) {
        fun(new B());
        fun(new C());
    }
    public static void fun(A a){
        a.fun2();
        if(a instanceof B){
            B b = (B)a;
            b.fun3();
        }
        if (a instanceof C){
            C c = (C)a;
            c.fun4();
        }
    }
}

明白之后,要给出一个结论:

  • 为了保证对象的向下转型操作正确,在操作前最好加上instanceof关键字进行判断。

在继承关系中,父类的设计很重要。只要父类的设计合理了,则代码开发就非常的简便。


转载请注明来源