1. 다형성
- “다양한 형태”, “여러 형태”
- 한 객체가 여러 타입의 객체로 취급될 수 있는 능력
- 다형성 이루는 핵심 이론
- 다형적 참조
- 메서드 오버라이딩
1-1. 다형적 참조
📌 "부모는 자식 (자신 기준 모든 자식 타입) 을 담을 수 있다"
public class Parent {
public void parentMethod() {
System.out.pritnln("Parent.parentMethod");
}
}
public class Child extends Parent {
public void childMethod() {
System.out.println("Child.childMethod");
}
}
1-1-1. 부모 변수 → 부모 인스턴스 참조
Parent parent = new Parent();
parent.parentMethod();
- Parent 인스턴스 생성 ⇒ 자식 생성 x ⇒ 메모리 상에는 Parent만 생성됨
- 생성된 주소(참조값)을 parent 변수에 담아둠
- parent.parentMethod() ⇒ 인스턴스의 Parent 클래스의 parentMethod() 호출
1-1-2. 자식 변수 → 자식 인스턴스 참조
Child child = new Child();
child.childMethod();
- Child 인스턴스 생성 ⇒ 부모 생성됨 ⇒ 메모리 상 Child, Parent 모두 생성됨
- 생성된 주소(참조값)을 child 변수에 담아둠
- child.childMethod() ⇒ 인스턴스의 Child 클래스의 childMethod() 호출
1-1-3. 부모 변수 → 자식 인스턴스 참조 ⭐️ (다형적 참조)
📌 부모 타입 ⇒ 자식 타입 참조 가능!!
”부모는 자식을 담을 수 있다”
📌 반대로 자식 타입 ⇒ 부모 타입 참조 불가!
“자식은 부모를 담을 수 없다”Child polyChild = new Parent();// 컴파일 오류
Parent poly = new Child();
poly.parentMethod();
// 자식의 메서드는 호출 불가!
// poly.childMethod();
- 부모 타입의 변수가 자식 인스턴스를 참조함
- Child 인스턴스 생성 ⇒ Parent, Child 모두 메모리에 생성됨
- 생성된 참조값을 Parent 타입 변수 (poly) 에 저장
- Parnet 타입이므로 자식 타입인 Child 의 메서드 실행 불가!
⇒ (상속관계) 참조 변수 자기 자신부터 시작해서 부모로 올라가면서 메서드 찾기 때문!
1-2. 다형성과 캐스팅
1-2-0. 캐스팅
- (타입) : 특정 타입으로 변경하는 것
- 캐스팅 종류
- 업캐스팅 (UpCasting) : 부모 타입으로 변경
- 다운캐스팅(DownCasting) : 자식 타입으로 변경
1-2-1. 업캐스팅
- 현재 타입을 부모 타입으로 바꾸는 것
Child child = new Child();
// 1. 업캐스팅 생략 안함
Parent parent1 = (Parent) child;
// 2. 업캐스팅 생략 -> 생략 권장
Parent parent2 = child;
📌 업캐스팅은 생략 가능 ⇒ 자주 사용하므로 생략 권장!
1-2-2. 다운캐스팅
- 부모 타입을 자식 타입으로 바꾸는 것
Parent poly = new Child();
// poly.childMethod(); // 자식 기능 호출 불가, 컴파일 에러
// 다운 캐스팅 : Parent -> Child
Child child = (Child) poly;
child.childMethod(); // 자식 타입이므로 호출 가능
- 다운캐스팅 순서 (참조값 대입)
Child child = (Child) poly; // 다운 캐스팅 시도
Child child = (Child) x001; // 참조값 읽음 => 자식 타입으로 지정
Child child = x001; // Child 참조변수에 참조값 대입
- ⭐ 다운캐스팅 주의점
Parent parent1 = new Child(); // 다형적 참조 (or 업캐스팅)
Child child1 = (Child) parent1;
child1.childMethod(); // 실행 ok
Parent parent2 = new Parent();
// Child child2 = (Child) parent2; // 런타임 에러 (ClassCastException)
// child2.childMethod(); // 실행 불가!!
1. Parent1과 Child1 ⇒ 다운캐스팅 해도 문제 없음!
2. Parent2와 Child2 ⇒ 메모리 상 자식 클래스가 존재하지 않으므로 다운캐스팅 불가! (런타임 에러)
"생성한 인스턴스에 하위 타입이 생성되었는지 확인하고 다운캐스팅 하자!"
- 업캐스팅과 다운캐스팅
- 업캐스팅 : 객체 생성 시 상위 부모 타입은 모두 메모리에 같이 생성됨 ⇒ 따라서 안전하게 캐스팅 가능!
- 다운캐스팅 : 객체 생성 시 하위 자식 타입은 메모리에 생성되지 않음 ⇒ 인스턴스에 존재하지 않는 하위
타입으로 캐스팅 가능성 발생 ⇒ 따라서 위험함 ⇒ 명시적 캐스팅 이유 : 개발자가 이러한 문제를 인지하고 사용해야 한다는 의미
1-3. instanceof
- 다형적 참조 ⇒ 객체는 다양한 자식을 대상으로 참조 가능
- 참조하는 대상이 다양하므로 어떤 인스턴스 참조하는지 확인 필요
- instanceof : 참조형 변수가 어떤 타입의 인스턴스를 참조하는 지 확인
📌 다운캐스팅 시 instanceof 사용 ⇒ 원하는 타입으로 다운캐스팅 가능한지 확인 먼저!
(참조형 변수) instanceof (클래스 or 인터페이스) => true / false 반환
// ex
Parent parent = new Parent();
Parent child = new Child();
parent instanceof Child // false 반환
child instanceof Child // true 반환
- true / false 기준
- 오른쪽 타입에 왼쪽의 인스턴스 타입이 들어갈 수 있는지 확인
- 가능하면 true, 불가능하면 false 반환
1-4. 다형성과 메서드 오버라이딩
📌 메서드 오버라이딩 기억할 점 단 한가지
오버라이딩 된 메서드가 항상 우선권을 가짐!!
- 메서드 오버라이딩
public class Parent {
public String value = "parent";
public void method() {
System.out.println("Parent.method");
}
}
...
public class Child extends Parent {
public String value = "child";
@Override
public void method() {
System.out.println("Child.method");
}
}
1-4-1. 자식 변수가 자식 인스턴스 참조
Child child = new Child();
System.out.println("value = " + child.value);
child.method();
/* 실행결과
value = child
Child.method
*/
1-4-2. 부모 변수가 부모 인스턴스 참조
Parent parent = new Parent();
System.out.println("value = " + parent.value);
parent.method();
/* 실행결과
value = parent
Parent.method
*/
1-4-3. 부모 변수가 자식 인스턴스 참조 (다형적 참조) ⭐️
Parent poly = new Child();
System.out.println("value = " + poly.value);
poly.method();
/* 실행결과
value = parent
Child.method
*/
- poly.value
- 자기 타입의 멤버 변수 접근 (만약 멤버 변수가 없다면 하위 타입에서 찾음)
- 멤버 변수(필드) 는 오버라이딩 불가!
- poly.method()
- 자기 타입의 메서드 접근 ⇒ 하위 타입에서 오버라이딩 발견
- 오버라이딩 된 메서드는 항상 우선권을 가짐!!! ⇒ 따라서 child.method 실행된 것
1-5. 정리
⭐ 다형성 정리
1. 다형적 참조
: 하나의 변수 타입으로 하위(자식) 인스턴스 참조 가능
2. 메서드 오버라이딩
- 기존 메서드를 하위 타입에서 재정의
- 오버라이딩 된 메서드는 항상 우선권을 가짐!
'Java' 카테고리의 다른 글
[Java] static (0) | 2024.07.09 |
---|---|
[Java] 객체 지향 프로그래밍 - 추상화 (Abstraction) (0) | 2024.07.09 |
[Java] 객체 지향 프로그래밍 - 상속 (Inheritance) (0) | 2024.07.08 |
[Java] 객체 지향 프로그래밍 - 캡슐화 (Encapsulation) (0) | 2024.07.08 |
[Java] 접근 제어자 (Access Modifier) (0) | 2024.07.08 |