다형성을 실현하기 위해서는 업캐스팅과 다운캐스팅에 대한 이해가 필요하다.
자바에서 서브 클래스는 슈퍼 클래스의 속성을 상속받기 때문에 서브 클래싀 객체는 슈퍼 클래싀 멤버를 모두 가진다. 그러므로 서브 클래스의 객체를 슈퍼 클래싀 객체로 취급할 수 있다.
서브 클래스의 객체에 대한 래퍼런스를 슈퍼 클래스 타입으로 변환하는 것을 업캐스팅이라고 한다.
업캐스팅한 래퍼런스로는 객체 내에 모든 멤버에 접근할 수 없고 슈퍼 클래스의 멤버에만 접근할 수 있다. 따라서 위 그림에 있는 예제를 보면 Student 객체가 Person 타입으로 업캐스팅되며느 Person 타입의 객체로 취급되며 Student 클래스의 필드나 메서드에는 접근할 수 없게 된다. 그렇기 때문에 업캐스팅시에는 명시적으로 형변환 할 필요가 없다. 자동으로 형변환이 되기 때문이다.
단, 오버라이딩 된 멤버인 경우 업캐스팅 여부 상관없이 서브 클래스에서 오버라이딩 한 멤버로 접근한다. 오버라이딩 된 멤버는 동적 바인딩을 통해 런타임 때 실행되는데, JVM이 메서드 호출시 참조변수의 자료형이 아니라 실제 객체의 자료형을 중심으로 동작하기 때문이다.
서브 클래스형 참조변수는 상위 클래스 객체를 가리킬 수 없다. 따라서 아래와 같이 작성하면 오류가 발생한다.
UnviStudent s = new Person(); // 컴파일 에러
UnviStudent s = (UnviStudent) new Person(); // 런타임 에러 발생
제대로된 다운 캐스팅은 아래와 같다.
Person p = new UnviStudent();
UnviStudent s = (UnviStudent) p;
이렇게만 가능한 이유는 p는 Person 타입이므로 Student 객체 내에 있는 Person 객체를 가리킨 것인데, 이를 다시 Student 객체 전체를 가리키도록 한 것이기 때문이다.
즉, 반드시 객체의 실제 자료형으로만 다운 캐스팅이 가능하다.
업캐스팅을 통해 부모 타입에 자식 객체를 할당할 수 있음을 알았다. 그리하여 이를 객체 배열에 저장하여 유연하게 프로그래밍을 할 수 있게 되는데 이것이 바로 다형성이다.
Person[] plist = new Person[2];
plist[0] = new Person();
plist[1] = new UnivStudent();
그럼 이를 유연하게 활용하기 위해서는 부모 타입의 참조변수에 어떤 자식 객체가 할당되어 있어야 하는지 알아야 한다. 이를 판별해 주는 키워드가 instanceof
이다.
instanceof 연산자는 참조변수가 참조하고 있는 객체가 명시한 클래스로부터 생성되었는지를 검사하고, boolean 결과값을 반환한다. 사용 방법은 아래와 같다.
for(Person p : plist) {
p.WharYourName();
if(p instanceof UnivStudent)
((UnivStudent) p).WhoAreYou();
}
사용시 주의할 점은 서브 클래스에서 추가된 멤버 접근시에만 확인 하는 것이 좋다.
업캐스팅은 자식 클래스의 객체를 부모 클래스 타입으로 참조하는 것이라 했습니다. 업캐스팅의 근본적인 이유는 상속의 특성에 있습니다. 자식 클래스는 부모 클래스를 상속받기 때문에, 자식 클래스 내부에는 부모 클래스의 모든 필드와 메서드가 포함됩니다. 따라서 자식 클래스 객체는 부모 클래스 타입으로도 참조될 수 있습니다. 업캐스팅은 자식 클래스에서 추가된 기능에는 접근할 수 없지만, 부모 클래스에서 정의된 메서드와 필드에 접근할 수 있습니다.
업캐스팅의 장점은 다형성을 활용할 수 있다는 점입니다. 여러 자식 클래스를 부모 클래스 타입으로 묶어 공통된 인터페이스를 사용할 수 있게 됩니다.
다운캐스팅은 부모 클래스 타입으로 참조된 객체를 다시 자식 클래스 타입으로 변환하는 것을 의미합니다. 다운캐스팅을 사용하는 이유는 자식 클래스에서 추가된 기능을 사용하기 위해서입니다. 그러나, 다운캐스팅은 항상 안전하지 않기 때문에 타입 검사를 해야 하며, instanceof
연산자를 사용하여 타입을 확인하는 것이 일반적입니다.
Animal animal = new Dog(); // 업캐스팅
Dog dog = (Dog) animal; // 다운캐스팅
다운캐스팅이 가능한 이유는 자식 클래스 객체 내부에 부모 클래스의 특성이 포함되어 있기 때문입니다. 자식 클래스는 부모 클래스의 모든 속성과 메서드를 물려받기 때문에, 부모 클래스 타입으로 선언된 변수를 자식 클래스 타입으로 되돌릴 수 있습니다. 단, 실제로 그 객체가 해당 자식 클래스 타입인지 반드시 확인해야 하며, 그렇지 않으면 ClassCastException
이 발생할 수 있습니다.
public boolean equals(Object obj) {
boolean result = false;
if(boj != null && obj instanceof Person) {
Person p = (Person) obj;
if(age == p.age && name.equals(p.name))
result = true;
}
return result;
}
출처
명품 JAVA programming - 황기태, 김효수
https://www.youtube.com/사람만이