Статьи

Полиморфизм времени исполнения в Java

Довольно давно я писал о Overriding v / s Hiding . В этом посте я хотел бы кратко объяснить с примерами полиморфизма во время выполнения в Java. Этот пост должен был быть написан до Overriding v / s Hiding , но лучше поздно, чем никогда.

Давайте рассмотрим следующее Vehicleи Carи Truckкласс:

class Vehicle{
  public void drive(){
    System.out.println("Driving vehicle ...");
  }
}
 
class Car extends Vehicle{
  @Override
  public void drive(){
    System.out.println("Driving car...");
  }
}
 
class Truck extends Vehicle{
  @Override
  public void drive(){
    System.out.println("Driving truck...");
  }
   
  public void load(){
    System.out.println("Loading truck...");
  }
}

А Vehicleможно управлять, так же как Carи Truck. Но в дополнение к этому Truckможно загружать товары. Давайте создадим экземпляры этих классов и drive()их и попробуем также load()грузовик.

public class RunTimePolymorphismDemo {
  public static void main(String[] args) {
    Vehicle vehicle = new Vehicle();
    vehicle.drive();
     
    Vehicle carVehicle = new Car();
    carVehicle.drive();
     
    Vehicle truckVehicle = new Truck();
    truckVehicle.drive();
     
    //Compile time error
    //truckVehicle.load();
     
    Truck truck = new Truck();
    truck.load();
  }
}

И вывод:

Driving vehicle ...
Driving car...
Driving truck...
Loading truck...

Если бы не задействованный полиморфизм времени исполнения, результат был бы: Driving vehicle ...для всех трех вызовов drive()метода. Вы также можете увидеть, что это truckVehicle.drive()приводит к ошибке времени компиляции. Так что же происходит в приведенном выше коде?

Любое объявление и создание объекта состоит из двух частей: тип ссылки и тип созданного объекта. Например, в Vehicle carVehicle = new Car()ссылочном типе Vehicleи созданный объект имеет тип Car. Такое присвоение возможно только в том случае, если созданный объект типа является подклассом ссылочного типа, т.е. в случаях, когда используется наследование.

Каждая ссылка на объект может использоваться для вызова методов, и методы, которые могут быть вызваны, определяются на основе ссылочного типа. И это решается во время компиляции. Но реализация, которая будет вызвана, определяется на основе типа созданного объекта. В приведенном выше примере: carVehicle.drive()компилируется, потому что drive()метод является частью Vehicleкласса и дает Driving car...в качестве выходных данных, потому что метод переопределяется Carклассом. На аналогичных строках: truckVehicle.load()выдает ошибку времени компиляции, потому что метод load()не является частью Vehicleкласса, но определяется только в Truckклассе. Но truck.load()компилируется, потому что ссылочный тип является Truckклассом, и компилятор может разрешить load()метод.

Чтобы подвести итог:

  • Привязка метода происходит во время компиляции, то есть какие методы могут быть вызваны для данного ссылочного типа, определяется во время компиляции.
  • Выбор реализации метода для выполнения происходит во время выполнения, т. Е. Какая реализация метода, который должен быть выполнен, т.е. версия суперкласса или одна из версий подкласса, определяется во время выполнения, и именно это приводит к полиморфизму времени выполнения.

Есть много мест, где задействован полиморфизм времени исполнения, но я не могу сказать ни одного из них: Dependency Injection, Coding to Interface .