자바-다형성
다형성은 객체가 다양한 형태를 취하는 능력입니다. 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 ()를 호출합니다.
이 동작을 가상 메서드 호출이라고하며 이러한 메서드를 가상 메서드라고합니다. 재정의 된 메서드는 컴파일 타임에 소스 코드에서 사용 된 참조 데이터 유형에 관계없이 런타임에 호출됩니다.