Java Note 4

Java 多态

Posted by JH on August 23, 2020

1.多态性的理解

可以理解为一个事物的多种形态。比如数据库的连接方式,我们定义好了数据库的连接,也规定了连接时的步骤, 但是我们并不知道用户会采用什么数据库,在没有多态以前我们只能针对不同的数据库写不同的连接方法, 而有了多态以后我们只需要定义好数据库的类并书写好连接方法,让所有的数据库继承数据库类并重写数据库连接方法。

这样我们在调用的时候只需要通过声明数据库类并指向数据库的子类的方式, (即数据库类的引用指向继承了数据库类的具体实现类的对象)就可以进行数据库连接。 而不是需要针对不同的数据库书写不同的连接方式。

对象的多态性:父类的引用指向子类的对象(或子类的对象赋给父类的引用)

编译时和运行时类型不一致,产生了多态

代码举例:

Person p = new Man();
Object obj = new Date();

2.多态性的使用:虚拟方法调用

  • 有了对象的多态性以后,我们在编译期,只能调用父类中声明的方法,但在运行期,我们实际执行的是子类重写父类的方法。

  • 对象的多态:在Java中,子类的对象可以替代父类的对象使用

    一个变量只能有一种确定的数据类型

    一个引用类型变量可能指向(引用)多种不同类型的对象

2.1多态性的使用前提

  1. 类的继承关系

  2. 方法的重写

2.2多态性的应用举例

public class A {
    public String show(D obj) {
        return ("A and D");
    }

    public String show(A obj) {
        return ("A and A");
    } 

}

public class B extends A{
    public String show(B obj){
        return ("B and B");
    }
    
    public String show(A obj){
        return ("B and A");
    } 
}

public class C extends B{

}

public class D extends B{

}

public class Test {
    public static void main(String[] args) {
        A a1 = new A();
        A a2 = new B();
        B b = new B();
        C c = new C();
        D d = new D();
        
        System.out.println("1--" + a1.show(b));
        System.out.println("2--" + a1.show(c));
        System.out.println("3--" + a1.show(d));
        System.out.println("4--" + a2.show(b));
        System.out.println("5--" + a2.show(c));
        System.out.println("6--" + a2.show(d));
        System.out.println("7--" + b.show(b));
        System.out.println("8--" + b.show(c));
        System.out.println("9--" + b.show(d));      
    }
}

结果如下:

1--A and A
2--A and A
3--A and D
4--B and A
5--B and A
6--A and D
7--B and B
8--B and B
9--A and D

2.3 多态性使用的注意点

  • 对象的多态性,只适用于方法,不适用于属性

  • 引用类型变量如果声明为父类的类型,但实际引用的是子类对象, 那么该变量就不能再访问子类中添加的属性和方法

  • 多态是运行时行为

2.4 多态性使用总结

  • 多态的作用:提高了代码的通用性,常称作接口重用

  • 使用前提:需要存在继承或者实现关系;有方法的重写

  • 成员方法:

    编译时:要查看引用变量所声明的类中是否有所调用的方法

    运行时:调用实际new的对象所属的类中的重写方法

  • 成员变量:不具备多态性,只看引用变量所声明的类

3.向下转型

3.1 为什么使用向下转型

有了对象的多态性以后,内存中实际上是加载了子类特有的属性和方法的, 但是由于变量声明为父类类型,导致编译时,只能调用父类中声明的属性和方法。 子类特有的属性和方法不能调用。

由于向上转型(在继承层次中向上移动)会丢失具体的类型信息,那么为了重新获取类型信息,、 就需要在继承层次中向下移动,使用向下转型。

向上转型永远是安全的,因为基类不会具有比派生类更多的接口。 因此,每条发送给基类接口的消息都能被接收。但是对于向下转型, 你无法知道一个形状是圆,它有可能是三角形、正方形或其他一些类型。

问:如何才能调用子类特的属性和方法?
答:使用向下转型。

3.2 如何实现向下转型

使用强制类型转换符:()

Person p = new Man();
Man m = (Man) p;

3.3 使用时的注意点

  1. 使用强转时,可能出现ClassCastException的异常。

  2. 为了避免在向下转型时出现ClassCastException的异常,我们在向下转型之前,先进行instanceof的判断,一旦返回true,就进行向下转型。如果返回false,不进行向下转型。

  3. 只有对象A是B的子类实例化对象或者在下层的子类,才能向下转型

3.4 instanceof的使用

  1. a instanceof A:==判断对象a==是否是==类A的实例==。如果是,返回true;如果不是,返回false。

  2. 如果 a instanceof A返回true,则 a instanceof B也返回true.其中,类B是类A的父类。

  3. 要求a所属的类与类A必须是子类和父类的关系,否则编译错误。

4.多态性的实例

  • Object类中定义的public boolean equals(Object obj){ }

  • JDBC:使用Java程序操作(获取数据库连接、CRUD)数据库(MySQL、Oracle、DB2、SQL Server)

  • 抽象类、接口的使用肯定体现了多态性。(抽象类、接口不能实例化)