![[JAVA] 다형성](https://img1.daumcdn.net/thumb/R750x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMqqtv%2FbtsHR6q3Knh%2F9O2xufdmikGpdSm6qzfa60%2Fimg.png)
===다형성은 객체지향의 필수적인 요소이며 객체지향의 꽃이라고 불린다.===
다형성의 핵심이론
- 다형적 참조
- 메서드 오버라이딩
다형적 참조
부모타입의 변수가 부모 인스턴스 참조Parent parent = new Parent();
parent.parentMethod();
자식변수가 자식 인스턴스 참조Child child = new Child();
child.parentMethod();
child.childMethod();
- child변수는 Parent인스턴스와 Child인스턴스를 모두 가지고있다.
- 자식인스턴스에서 메서드를 먼저 찾아보고 없으면 부모 메서드를 호출한다.
부모변수가 자식 인스턴스 참조(다형적참조)Parent poly = new Child();
poly.parentMethod();
- 부모타입의 변수가 자식 인스턴스를 참조
- 부모와 자식인스턴스 모두 생성
- 부모타입은 자식타입을 담을 수 있다
- poly의 타입은 Parent타입이기때문에 부모의 메서드를 호출한다
- 자식의 메서드는 호출할 수 없으며 만약 하고싶다면 캐스팅을 해야한다
다형성과 캐스팅
업캐스팅: 자식타입을 부모 타입으로 변경
다운캐스팅: 부모타입을 자식타입으로 변경
Parent poly = new Parent();
===poly.childMethod(); //에러 발생===
Child child = (child)poly; -> 다운캐스팅으로인해 poly는 Child타입을 갖게됨
public static void main(String[] args) {
//부모타입 - 부모메서드
Parent parent = new Parent();
parent.parentMethod();
//자식타입 - 부모메서드 / 자식메서드
Child child = new Child();
child.parentMethod();
child.childMethod();
//부모타입에 자식인스턴스 생성 - 부모타입 변수에서는 자식메서드 호출불가
//다운캐스팅 필요
Parent poly = new Child();
poly.parentMethod();
Child polyChild = (Child) poly;
polyChild.childMethod();
}
캐스팅의 종류
임시캐스팅((Child) poly).childMethod
.연산자가 (Child)보다 연산자 우선순위를 갖기 때문에 이와 같이 괄호를 사용하면 변수사용없이 임시로 다운캐스팅을 할 수 있다.
업캐스팅Child child = new Child();
Parent parent = child
//(Child)가 생략되어있다.
다운캐스팅
다운캐스팅은 잘못할경우 심각한 런타임에러가 나타날 수 있다.
Parent parent1 = new Parent();
Child child1 = (Child) parent1;
child1.parentMethod();
child1.childMethod();
parent1변수가 생성될 때 Parent인스턴스로 생성되었기 떄문에 애초에 Child인스턴스는 내부적으로 생성되어 있지 않다.
그렇기때문에 childMethod자체를 사용할 수 없으며 이전에 parent1변수를 Child타입으로 다운캐스팅하는 과정에서 ClassCastException이 발생하게된다.
이와 같은 문제로 업캐스팅과 다운캐스팅의 차이를 설명할 수 있다.
업캐스팅은 자식을 부모타입으로 형변환하는 것인데, 만약 자식타입으로 객체가 생성되었다면 이미 참조값에 있는 인스턴스에 내부적으로 부모의 인스턴스도 생성되어있기때문에 자식 메서드, 부모 메서드 모두 사용할 수 있기때문에 업캐스팅을 하는것에는 문제가 되지 않는다
반면 다운캐스팅은 부모타입으로 객체를 생성할 때 부모타입의 메서드는 내부적으로 생성이되지만 자식타입의 메서드, 필드는 생성되지 않는다. 때문에 다운캐스팅을 할 때는 개발자가 이를 인지하고 사용해야하기 때문에 명시적으로 다운캐스팅을 해야한다.
instanceof
Parent parent = new Child();
이와 같이 부모타입에 자식타입의 인스턴스를 생성하게 되면 참조값에 내부적으로는 자식타입의 인스턴스와 부모타입의 인스턴스가 모두 생성된다고 공부했다.
이 때, parent라는 참조변수에 어떤 인스턴스가 들어있는지 확인할 수 있는 기능을 수행하는게 ===instanceof===키워드이다.
public static void main(String[] args) {
Parent parent = new Parent();
call(parent);
Parent parent1 = new Child();
call(parent1);
}
private static void call(Parent parent) {
if (parent instanceof Child) {
System.out.println("Child 인스턴스가 맞습니다");
Child child = (Child) parent;
child.childMethod();
}else{
System.out.println("Child 인스턴스가 아닙니다.");
}
}
위와같이 instanceof를 사용하여 안전하게 다운캐스팅을 수행할 수 있다
다형성과 메서드 오버라이딩
Parent parent = new Child();
이 때 parent참조 변수에서 부모와 자식 클래스에 같은이름으로 선언된 메서드 method()를 호출한다면 method메서드는 재정의된 메서드이기 때문에 반드시 오버라이딩된 메서드가 호출된다.
즉, 자식의 메서드가 호출되게된다. 이와 같이 자식에서 오버라이딩된 메서드가 있다면 해당 메서드가 우선순위를 갖게 된다.
반면 필드값은 재정의되지 않으며 반드시 부모의 필드의 값을 호출하게된다.
다형성 활용
public static void main(String[] args) {
Animal[] animals = {new Cow(), new Cat(), new Dog()};
for (Animal animal : animals) {
soundTest(animal);
}
}
private static void soundTest(Animal animal) {
System.out.println("동물 소리 테스트 시작");
animal.sound();
System.out.println("동물 소리 테스트 종료");
}
위와 같이 다형성과 상속을 활용하여 코드의 중복없이 동물의 울음소리를 객체별로 구현할 수 있었다.
하지만 위와 같은 코드에서는 2가지의 문제점이 있다.
- Animal클래스를 직접 생성함으로써 Animal클래스에 있는 원초적인 sound()메서드를 사용할 수 있다.
- 상속받은 자식클래스에서 깜빡하고 메서드를 재정의하지 않았을 경우 런타임 문제가 발생할 수 있다.
이 문제를 해결하기위해 ===추상클래스===를 제공한다.
공부자료 참조: 인프런 - 김영한
https://www.inflearn.com/users/74366/@yh
'Language > Java' 카테고리의 다른 글
[JAVA - 자료구조] ArrayList (1) | 2024.06.07 |
---|---|
[JAVA] 중첩 클래스 (중첩 클래스 ,정적 중첩 클래스, 지역 클래스) (0) | 2024.06.03 |
[Java] - 배열(Array) (0) | 2023.10.23 |
[Java] - BufferedWriter (0) | 2023.10.18 |
[Java] - BufferedReader (0) | 2023.10.18 |
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!