다형성은 "하나의 객체가 여러 가지 형태를 가질 수 있는 성질"을 의미하며, 자바에서 상속 관계를 기반으로 구현된다. 다형성을 통해 부모 클래스의 참조 변수가 여러 자식 클래스의 객체를 참조할 수 있으며, 오버라이딩된 메서드를 자식 클래스에 맞게 호출할 수 있다.
부모 클래스 타입의 변수가 여러 자식 클래스 객체를 하나의 타입으로 다룰 수 있다는 것을 의미한다. 즉, 부모 클래스 타입의 변수를 사용하여 다양한 자식 클래스의 인스턴스를 저장하거나 호출할 수 있다는 것이다.
상속 관계
오버라이딩된 메서드 호출
참조 자료형의 형변환
다형성(Polymorphism)은 자바의 상속 구조에서 중요한 개념으로, 상속 관계에 있는 클래스에서 형변환을 통해 다양한 형태로 객체를 다룰 수 있게 해준다. 업캐스팅과 다운캐스팅은 이러한 다형성을 구현하는 데 사용되는 형변환 기법이다.
class Parent { }
class Child extends Parent { }
class Unrelated { }
Parent p = new Parent();
Child c = new Child();
Unrelated u = new Unrelated();
// 형변환 가능
p = c; // 자식 -> 부모 (업캐스팅)
// 형변환 불가
// p = u; // 컴파일 에러 (상속 관계가 없기 때문에 형변환 불가)
class Parent {
void show() {
System.out.println("Parent의 메서드");
}
}
class Child extends Parent {
void show() {
System.out.println("Child의 메서드");
}
}
public class Main {
public static void main(String[] args) {
Parent p = new Child(); // 업캐스팅
p.show(); // 자식 클래스의 오버라이딩된 메서드 호출 -> "Child의 메서드"
}
}
ClassCastException
이 발생한다. 따라서, 형변환 전에 instanceof
연산자로 타입을 체크하는 것이 안전하다.class Parent {
void show() {
System.out.println("Parent의 메서드");
}
}
class Child extends Parent {
void play() {
System.out.println("Child의 메서드");
}
}
public class Main {
public static void main(String[] args) {
Parent p = new Child(); // 업캐스팅
// p.play(); // 컴파일 에러: Parent 타입으로 play() 호출 불가
// 다운캐스팅
Child c = (Child) p; // 부모 -> 자식 (명시적 다운캐스팅)
c.play(); // "Child의 메서드" 출력
}
}
Parent
타입의 참조 변수 p
는 실제로 Child
객체를 가리키고 있으므로 다운캐스팅이 가능하며, 다운캐스팅 후 자식 클래스의 메서드인 play()
를 호출할 수 있다.ClassCastException
발생다운캐스팅이 잘못된 객체로 시도되면 런타임 에러가 발생
public class Main {
public static void main(String[] args) {
Parent p = new Parent();
Child c = (Child) p; // 런타임 에러: ClassCastException
}
}
instanceof
사용)if (p instanceof Child) {
Child c = (Child) p;
c.play();
}
instanceof
연산자를 사용하여 참조 변수가 실제로 자식 타입의 객체인지 확인한 후 다운캐스팅을 진행하면 안전하다.instanceof
키워드object instanceof Type
object
: 확인할 객체Type
: 클래스나 인터페이스true
또는 false
로, 객체가 해당 클래스나 인터페이스의 인스턴스인지 여부를 반환항목 | 업캐스팅 (Upcasting) | 다운캐스팅 (Downcasting) |
---|---|---|
설명 | 자식 클래스를 부모 클래스로 형변환. | 부모 클래스를 자식 클래스로 형변환. |
형변환 방식 | 자동 형변환 가능 (형변환 생략 가능). | 명시적 형변환 필요 ((자식클래스) 형식). |
안전성 | 항상 안전하며, 오류가 발생하지 않음. | 자식 객체를 참조하지 않으면 ClassCastException 발생 가능. |
사용 범위 | 부모 클래스의 멤버(필드/메서드)만 접근 가능. | 자식 클래스의 멤버(필드/메서드)에 접근 가능. |
오버라이딩 메서드 | 부모 타입으로 호출해도 자식 클래스의 오버라이딩된 메서드 호출. | 다운캐스팅 후 자식 클래스의 메서드나 필드에 접근 가능. |
class Animal {
void sound() {
System.out.println("동물 소리");
}
}
class Dog extends Animal {
@Override
void sound() {
System.out.println("멍멍");
}
void bark() {
System.out.println("짖다");
}
}
class Cat extends Animal {
@Override
void sound() {
System.out.println("야옹");
}
}
public class Main {
public static void main(String[] args) {
Animal a = new Dog(); // 업캐스팅 (자동 형변환)
a.sound(); // "멍멍" (오버라이딩된 메서드 호출)
// 다운캐스팅
if (a instanceof Dog) {
Dog d = (Dog) a; // 안전한 다운캐스팅
d.bark(); // "짖다"
}
// 잘못된 다운캐스팅 (런타임 에러)
// Cat c = (Cat) a; // ClassCastException 발생
}
}
Animal
타입으로 자식 객체를 다루며, 다형성을 통해 오버라이딩된 메서드를 호출할 수 있다.
- 업캐스팅은 항상 가능하고, 부모 클래스의 참조 변수로 자식 객체를 참조할 수 있다.
- 다운캐스팅은 명시적인 형변환이 필요하며, 참조 변수가 실제로 가리키고 있는 객체가 자식 클래스여야만 가능하다. 안전한 다운캐스팅을 위해
instanceof
연산자로 타입을 확인하는 것이 좋다.