Учебники

Ява — полиморфизм

Полиморфизм — это способность объекта принимать различные формы. Наиболее распространенное использование полиморфизма в ООП происходит, когда ссылка на родительский класс используется для ссылки на объект дочернего класса.

Любой объект Java, который может пройти более одного теста IS-A, считается полиморфным. В Java все объекты Java являются полиморфными, поскольку любой объект будет проходить тест IS-A для своего собственного типа и для класса Object.

Важно знать, что единственный возможный способ получить доступ к объекту — через ссылочную переменную. Ссылочная переменная может быть только одного типа. После объявления тип ссылочной переменной не может быть изменен.

Ссылочная переменная может быть переназначена другим объектам при условии, что она не объявлена ​​как финальная. Тип ссылочной переменной будет определять методы, которые она может вызывать для объекта.

Ссылочная переменная может ссылаться на любой объект своего объявленного типа или любой подтип своего объявленного типа. Ссылочная переменная может быть объявлена ​​как класс или тип интерфейса.

пример

Давайте посмотрим на пример.

public interface Vegetarian{}
public class Animal{}
public class Deer extends Animal implements Vegetarian{}

Теперь класс Deer считается полиморфным, поскольку он имеет множественное наследование. Следующее верно для приведенных выше примеров —

  • Олень — это животное
  • Олень-вегетарианец
  • Олень есть олень
  • Олень-это объект

Когда мы применяем факты ссылочной переменной к ссылке на объект Deer, следующие объявления являются допустимыми:

пример

Deer d = new Deer();
Animal a = d;
Vegetarian v = d;
Object o = d;

Все ссылочные переменные d, a, v, o ссылаются на один и тот же объект Deer в куче.

Виртуальные методы

В этом разделе я покажу вам, как поведение переопределенных методов в Java позволяет вам использовать преимущества полиморфизма при разработке ваших классов.

Мы уже обсуждали переопределение метода, где дочерний класс может переопределять метод в своем родителе. Переопределенный метод по существу скрыт в родительском классе и не вызывается, если дочерний класс не использует ключевое слово super в переопределяющем методе.

пример

/* File name : Employee.java */
public class Employee {
   private String name;
   private String address;
   private int number;

   public Employee(String name, String address, int number) {
      System.out.println("Constructing an Employee");
      this.name = name;
      this.address = address;
      this.number = number;
   }

   public void mailCheck() {
      System.out.println("Mailing a check to " + this.name + " " + this.address);
   }

   public String toString() {
      return name + " " + address + " " + number;
   }

   public String getName() {
      return name;
   }

   public String getAddress() {
      return address;
   }

   public void setAddress(String newAddress) {
      address = newAddress;
   }

   public int getNumber() {
      return number;
   }
}

Теперь предположим, что мы расширяем класс Employee следующим образом:

/* File name : Salary.java */
public class Salary extends Employee {
   private double salary; // Annual salary
   
   public Salary(String name, String address, int number, double salary) {
      super(name, address, number);
      setSalary(salary);
   }
   
   public void mailCheck() {
      System.out.println("Within mailCheck of Salary class ");
      System.out.println("Mailing check to " + getName()
      + " with salary " + salary);
   }
   
   public double getSalary() {
      return salary;
   }
   
   public void setSalary(double newSalary) {
      if(newSalary >= 0.0) {
         salary = newSalary;
      }
   }
   
   public double computePay() {
      System.out.println("Computing salary pay for " + getName());
      return salary/52;
   }
}

Теперь вы внимательно изучаете следующую программу и пытаетесь определить ее результат:

/* File name : VirtualDemo.java */
public class VirtualDemo {

   public static void main(String [] args) {
      Salary s = new Salary("Mohd Mohtashim", "Ambehta, UP", 3, 3600.00);
      Employee e = new Salary("John Adams", "Boston, MA", 2, 2400.00);
      System.out.println("Call mailCheck using Salary reference --");   
      s.mailCheck();
      System.out.println("\n Call mailCheck using Employee reference--");
      e.mailCheck();
   }
}

Это даст следующий результат —

Выход

Constructing an Employee
Constructing an Employee

Call mailCheck using Salary reference --
Within mailCheck of Salary class
Mailing check to Mohd Mohtashim with salary 3600.0

Call mailCheck using Employee reference--
Within mailCheck of Salary class
Mailing check to John Adams with salary 2400.0

Здесь мы создаем два объекта Salary. Один использует ссылку на зарплату s , а другой использует ссылку сотрудника e .

При вызове s.mailCheck () компилятор видит mailCheck () в классе Salary во время компиляции, а JVM вызывает mailCheck () в классе Salary во время выполнения.

mailCheck () для e совершенно другой, потому что e является ссылкой Employee. Когда компилятор видит e.mailCheck () , компилятор видит метод mailCheck () в классе Employee.

Здесь, во время компиляции, компилятор использовал mailCheck () в Employee для проверки этого оператора. Однако во время выполнения JVM вызывает mailCheck () в классе Salary.

Это поведение называется виртуальным вызовом метода, а эти методы называются виртуальными методами. Переопределенный метод вызывается во время выполнения, независимо от типа ссылки, которая использовалась в исходном коде во время компиляции.