자바 다형성
다형성은 동일한 행동이 여러 가지 다른 표현이나 형태를 가질 수 있는 능력입니다.
다형성은 객체의 다양한 표현을 구현한 것입니다.
실제로 F1 키를 누르면
AS 3 도움말 문서가 현재 Flash 인터페이스 아래에 나타나는 경우
Word의 현재 팝업이 Word 도움말인 경우
Windows에서 나타나는 것은 Windows 도움말 및 지원입니다.
동일한 이벤트가 다른 개체에서 발생하면 다른 결과가 생성됩니다.
다형성 존재에 필요한 세 가지 조건:
상속
Rewriting
상위 클래스 참조가 하위 클래스 객체를 가리킵니다
예:
Parent p = new Child();
메소드 호출 다형성 사용 먼저 상위 클래스에 해당 메소드가 있는지 확인하고, 존재하지 않으면 컴파일 오류가 발생하며 하위 클래스에서 동일한 이름의 메소드를 호출합니다.
다형성의 이점: 프로그램을 잘 확장할 수 있고 모든 클래스의 객체를 보편적으로 처리할 수 있습니다.
다음은 다형성 인스턴스의 데모입니다. 자세한 설명은 주석을 참조하세요.
public class Test { public static void main(String[] args) { show(new Cat()); // 以 Cat 对象调用 show 方法 show(new Dog()); // 以 Dog 对象调用 show 方法 Animal a = new Cat(); // 向上转型 a.eat(); // 调用的是 Cat 的 eat Cat c = (Cat)a; // 向下转型 c.work(); // 调用的是 Cat 的 catchMouse } public static void show(Animal a) { a.eat(); // 类型判断 if (a instanceof Cat) { // 猫做的事情 Cat c = (Cat)a; c.work(); } else if (a instanceof Dog) { // 狗做的事情 Dog c = (Dog)a; c.work(); } } } abstract class Animal { abstract void eat(); } class Cat extends Animal { public void eat() { System.out.println("吃鱼"); } public void work() { System.out.println("抓老鼠"); } } class Dog extends Animal { public void eat() { System.out.println("吃骨头"); } public void work() { System.out.println("看家"); } }
위 프로그램을 실행하면 출력 결과는 다음과 같습니다.
吃鱼 抓老鼠 吃骨头 看家 吃鱼 抓老鼠
virtual method
설계할 때 Java로 소개하겠습니다. 클래스, 반복됨 작성된 메소드의 동작이 다형성에 어떤 영향을 미치는지.
우리는 이미 메서드 재정의에 대해 논의했습니다. 즉, 하위 클래스가 상위 클래스의 메서드를 재정의할 수 있습니다.
하위 클래스 객체가 재정의된 메서드를 호출하면 상위 클래스의 재정의된 메서드가 아닌 하위 클래스의 메서드가 호출됩니다.
부모 클래스에서 재정의된 메서드를 호출하려면 super 키워드를 사용해야 합니다.
/* 文件名 : 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("Employee 构造函数"); this.name = name; this.address = address; this.number = number; } public void mailCheck() { System.out.println("邮寄支票给: " + 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 클래스를 상속한다고 가정합니다.
/* 文件名 : Salary.java */ /* 文件名 : Salary.java */ public class Salary extends Employee { private double salary; // 全年工资 public Salary(String name, String address, int number, double salary) { super(name, address, number); setSalary(salary); } public void mailCheck() { System.out.println("Salary 类的 mailCheck 方法 "); System.out.println("邮寄支票给:" + getName() + " ,工资为:" + salary); } public double getSalary() { return salary; } public void setSalary(double newSalary) { if(newSalary >= 0.0) { salary = newSalary; } } public double computePay() { System.out.println("计算工资,付给:" + getName()); return salary/52; } }
이제 다음 코드를 주의 깊게 읽고 출력을 시도합니다.
/* 文件名 : VirtualDemo.java */ public class VirtualDemo { public static void main(String [] args) { Salary s = new Salary("员工 A", "北京", 3, 3600.00); Employee e = new Salary("员工 B", "上海", 2, 2400.00); System.out.println("使用 Salary 的引用调用 mailCheck -- "); s.mailCheck(); System.out.println("\n使用 Employee 的引用调用 mailCheck--"); e.mailCheck(); } }
위 예제 컴파일 및 실행 결과는 다음과 같습니다.
Employee 构造函数 Employee 构造函数 使用 Salary 的引用调用 mailCheck -- Salary 类的 mailCheck 方法 邮寄支票给:员工 A ,工资为:3600.0 使用 Employee 的引用调用 mailCheck-- Salary 类的 mailCheck 方法 邮寄支票给:员工 B ,工资为:2400.0
예제 분석
예제에서는 두 개의 Salary 개체가 인스턴스화됩니다. 하나는 Salary를 사용하여 s를 참조하고 다른 하나는 Employee를 사용하여 e를 참조합니다.
s.mailCheck()가 호출되면 컴파일러는 컴파일 중에 Salary 클래스에 mailCheck()가 있음을 발견하고 실행 프로세스 JVM은 Salary 클래스의 mailCheck()를 호출합니다.
s.mailCheck()를 호출하면 JVM(Java Virtual Machine)이 Salary 클래스의 mailCheck() 메서드를 호출합니다.
e는 Employee에 대한 참조이므로 e의 mailCheck() 메서드를 호출하면 컴파일러는 mailCheck() 메서드를 찾기 위해 Employee 클래스로 이동합니다.
컴파일하는 동안 컴파일러는 Employee 클래스의 mailCheck() 메서드를 사용하여 명령문을 확인합니다. 그러나 실행 시 JVM(Java Virtual Machine)은 Salary 클래스의 mailCheck() 메서드를 호출합니다.
위의 전체 과정을 가상 메서드 호출이라고 하며, 그 메서드를 가상 메서드라고 합니다.
Java의 모든 메소드는 이러한 방식으로 표현될 수 있으므로 컴파일 타임에 소스 코드에서 참조되는 변수의 데이터 유형에 관계없이 재정의된 메소드를 런타임에 호출할 수 있습니다.