Java - полиморфизм
Полиморфизм - это способность объекта принимать разные формы. Наиболее распространенное использование полиморфизма в ООП происходит, когда ссылка на родительский класс используется для ссылки на объект дочернего класса.
Любой объект 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ссылка на сотрудника. Когда компилятор видит e.mailCheck () , компилятор видит метод mailCheck () в классе Employee.
Здесь, во время компиляции, компилятор использовал mailCheck () в Employee для проверки этого оператора. Однако во время выполнения JVM вызывает mailCheck () в классе Salary.
Такое поведение называется вызовом виртуального метода, а эти методы называются виртуальными методами. Переопределенный метод вызывается во время выполнения, независимо от того, какой тип данных используется в исходном коде во время компиляции.