Java 多态

  一、多态介绍

  继承提高了代码的重用性,让类和类之间建立的联系,为多态创造了条件。

  1、什么是多态

  多态是指,在程序中定义的引用变量所指向的具体类型在编程时并不确定,而是在程序运行期间才确定。

  由于在程序运行时才确定具体的类型,即不修改程序的代码就可以改变程序运行时所绑定的具体代码,让程序选择多个运行状态,这就是多态性。

  2、多态的分类(主要指运行期)

  编译时多态:方法重载,系统在编译时确定调用重载函数的哪个版本

  运行时多态:运行时多态基于面向对象的继承性实现,它指父类型的引用可以指向子类型的对象,这就是向上转型。通过一个父类的引用发出的方法调用,执行的方法可能是在父类中的实现,也可能是在子类中的实现,这由运行时刻具体的对象类型决定。

  3、向上转型

  首先理解,子类是父类的特殊化,每个子类的实例也是其父类的实例,但是反过来就不成立。

  所以向上转型就是在允许的继承关系中,可以将子类对象赋值给父类型的引用的特性。

       反过来,会导致编译时错误。

       并且,通过这个父类的引用访问子类的对象时,只能访问父类中拥有的方法和属性。因为编译器认为引用是父类中的引用。

/*Bicycle是MountainBike的父类*/
Bicycle myBike=new MountainBike();

/*Object是所有类的父类*/
Object obj=new MountainBike();

  

  4、向下转型

  即把上转型中的父类型引用又赋值给一个子类型的引用,指向的仍然是这个子类型的对象。

       必须是显示的,即强制类型转换。

Object obj=new MountainBike();
MountainBike myBike=(MountainBike) obj;

   这一转换编译器会通过,但是如果在运行时obj不是MountainBike类型,会抛出异常。

  所以在这种情况下,为了避免运行时异常,我们可以使用instanceof操作符做逻辑测试:

if(obj instanceof MountainBike){
    MountainBike myBike=(MountainBike obj);
}

  在一个深层次的继承关系中,这种判断分支是一个噩梦。因而在设计良好的程序中,应该尽量避免这种判断分支!

  5、方法重写(override) 

  (父类子类同名方法的返回类型、参数的个数、类型与顺序必须保持一致)

        返回类型可以不同,但必须兼容,比如父类中的类型为某个类的对象,子类中的方法可以返回这个类或者它的子类。

  父类的静态方法不能被子类重写为非静态;

  父类的非静态方法不能被子类重写为静态。

  二、多态的实现

  子类继承父类后,父类型的引用变量既可以指向父类对象,也可以指向子类对象。

  当相同的消息发给一个对象引用时,该引用会根据具体指向子类还是父类对象而执行不同的行为。

  多态性就是相同的消息使得不同的对象作出不同的响应的机制。

  Java中有两种形式实现多态:继承和接口(接口后面讲)

  1、继承实现多态(多态发生在有继承关系的父类和子类间)

  通过继承实现多态有三个条件:继承关系、方法重写和向上转型(子类对象的引用赋值给父类型的引用变量)。

  只有满足了3个条件,才能在一个继承结构中使用统一的逻辑代码处理不同的对象,从而达到执行不同的动作的目的。

  (具体执行父类对象还是子类对象的方法,你看指向的内存是哪个的实例就好了)

public class Polymorphism {
    public static void main(String[] args) {
        Car sc = new ElectronicCar();
        sc.brake();
    }
}
class Car {
    public void brake() {
        System.out.println("SuperClass: I can brake.");
    }
}
class ElectronicCar extends Car {
    public void brake() {
        super.brake();
        System.out.println("SubClass: I can prevent collision~");
    }
}

   我们再看一个例子,更好地体会多态的优点:无论Car的子类如何变化,调用接口brakeInterface()保持不变。当brakeInterface()是给第三方使用时,接口方法保持稳定,可以不影响第三方的代码。

package test;

public class Polymorphism {
    public static void main(String[] args) {
        Car sc = new Car();
        brakeInterface(sc);
        sc=new ElectronicCar();
        brakeInterface(sc);
        sc=new HoveringCar();
        brakeInterface(sc);
    }

    public static void brakeInterface(Car sc){
        sc.brake();
    }
}
class Car {
    public void brake() {
        System.out.println("SuperClass: I can brake.");
    }
}
class HoveringCar extends Car{
    public void brake(){
        super.brake();
        System.out.println("This is Hovering car~ ");
    }
}
class ElectronicCar extends Car {
    public void brake() {
        super.brake();
        System.out.println("SubClass: I can prevent collision~");
    }
}

  2、关于equals()方法

  操作符“==”可以比较两个基本类型的变量是否相等。

  当我们使用它比较两个对象的引用变量,实际上实在比较两个引用变量是否指向了相同的对象。这里,相同的对象是指在堆中占用同一块内存单元中的同类型对象。

  如何比较两个对象的引用变量所指向的对象的内容是否相同?

  使用equals()方法(Object类中定义了,意味着每个类都会有这个方法),返回boolean。

  但是默认情况下,它比较的是对象的引用是否相同。

  String、Integer、Date中,equals()方法被重写了,比较的不是内存中的地址而是对象的内容。

  在自定义的类的对象中,equals()比较两个引用是否指向了同一个对象。因此,如果想比较对象的内容,在类中重写equals()吧!

  

原文地址:https://www.cnblogs.com/bigbigbigo/p/8421784.html