자바-다형성

다형성은 객체가 다양한 형태를 취하는 능력입니다. OOP에서 다형성의 가장 일반적인 사용은 부모 클래스 참조가 자식 클래스 개체를 참조하는 데 사용될 때 발생합니다.

둘 이상의 IS-A 테스트를 통과 할 수있는 모든 Java 객체는 다형성으로 간주됩니다. Java에서는 모든 객체가 자체 유형 및 객체 클래스에 대한 IS-A 테스트를 통과하므로 모든 Java 객체는 다형성입니다.

객체에 액세스 할 수있는 유일한 방법은 참조 변수를 통하는 것임을 아는 것이 중요합니다. 참조 변수는 한 가지 유형 만 될 수 있습니다. 일단 선언되면 참조 변수의 유형을 변경할 수 없습니다.

참조 변수는 final로 선언되지 않은 경우 다른 개체에 다시 할당 할 수 있습니다. 참조 변수의 유형은 개체에서 호출 할 수있는 메서드를 결정합니다.

참조 변수는 선언 된 유형의 모든 개체 또는 선언 된 유형의 하위 유형을 참조 할 수 있습니다. 참조 변수는 클래스 또는 인터페이스 유형으로 선언 할 수 있습니다.

예를 살펴 보겠습니다.

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

이제 Deer 클래스는 다중 상속이 있기 때문에 다형성으로 간주됩니다. 위의 예는 다음과 같습니다.

  • 사슴 IS-A 동물
  • 사슴 IS-A 채식주의 자
  • 사슴 IS-A 사슴
  • 사슴 IS-A 개체

참조 변수 팩트를 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 () 를 호출하는 동안 컴파일러는 컴파일 타임에 Salary 클래스에서 mailCheck ()를보고 JVM은 런타임에 Salary 클래스에서 mailCheck ()를 호출합니다.

mailCheck () on e 왜냐하면 e직원 참조입니다. 컴파일러가 e.mailCheck () 를 보면 컴파일러는 Employee 클래스의 mailCheck () 메서드를 봅니다.

여기서 컴파일 타임에 컴파일러는 Employee의 mailCheck ()를 사용하여이 문을 확인했습니다. 그러나 런타임에 JVM은 Salary 클래스에서 mailCheck ()를 호출합니다.

이 동작을 가상 메서드 호출이라고하며 이러한 메서드를 가상 메서드라고합니다. 재정의 된 메서드는 컴파일 타임에 소스 코드에서 사용 된 참조 데이터 유형에 관계없이 런타임에 호출됩니다.