다형성 : 사용 방법은 동일하지만 실행 결과가 다양하게 나오는 성질
다형성은, 반드시 부모-자식 개념이 있어야 가능하다.
객체 사용 방법이 동일하다? == 동일한 메소드를 가지고 있다.
Example)
금호 타이어와 한국 타이어가 타이어라는 클래스를 상속 받고 있다고 하자.
만약 한국 타이어와 금호 타이어가 ‘타이어’의 메소드를 오버라이딩하고 있다면, 해당 메소드를 호출 시 오버라이딩된 메소드가 호출된다. 물론, 오버라이딩된 내용은 두 타이어가 다르기 때문에 결과가 다르게 나온다.
다형성을 구현하기 위해서는 자동 타입 변환과 메소드 재정의가 필요하다.
자동 타입 변환 + 메소드 오버라이딩 → 다형성
필드 타입은 동일하지만(사용 방법은 동일하지만), 대입되는 객체가 달라져서 실행 결과가 다양하게 나올 수 있는 것을 말한다.
public class Car {
public Tire tire;
public void run() {
tire.roll();
// tire 필드에 대입된 객체의 roll() 메소드 호출
}
}
public class Tire {
public void roll() {
System.out.println("회전합니다.");
}
}
----
Car myCar = new Car();
myCar.tire = new HankookTire();
// HankookTire 클래스는 Tire 클래스를 상속받는 상태
메소드가 클래스 타입의 매개변수를 가지고 있을 경우, 호출할 때 동일한 타입의 객체를 제공하는 것이 정석이지만 자식 객체를 제공할 수도 있다. → 여기서 다형성 발생
public class Driver {
public void drive(Vehicle vehicle) {
vehicle.run();
}
}
Driver driver = new Driver();
Bus bus = new Bus();
driver.drive(Bus);
// Bus 클래스는 Vehicle 클래스를 상속 받는 상태
💡 **Instance of 연산자**
객체가 어떤 클래스인지, 어떤 클래스를 상속받았는지 확인하는 데 사용하는 연산자이다. 즉, 참조 변수가 참조하고 있는 인스턴스의 실제 타입을 알아보기 위해 해당 연산자를 사용한다.
class A { }
class B extends A { }
public static void main(String[] args]) {
A a = new A();
B b = new B();
System.out.println(a instanceof A); // true
System.out.println(b instanceof A); //true
System.out.println(a instanceof B); // false
상속의 다형성과 마찬가지로 인터페이스 역시 다형성을 구현하기 위해 재정의와 자동 타입 변환 기능을 이용한다.
→ 세 가지 모두 상속에서와 큰 차이 없음. 자세한 코드 및 설명은 373 ~ 387 페이지