티스토리 뷰
포스팅에 앞서 내용이 틀릴 수 있습니다.
해당 부분 지적 감사히 받습니다.
자바 다형성이다.
다형성이란 뭘까?
다형성(Polymorphism) : 하나의 객체가 다른 타입으로 사용될 수 있다.
다형성이 필요한 예시부터 먼저 이야기해 보자.
자동차라는 부모 Class가 있다.
자동차의 소분에는 경차, 소/중/대, 화물 등등 많은 종류로 다시 분류될 수 있다.
만약 자동차를 관리하는 프로그램이 있었는데, 새로운 자동차 종류가 나왔다고 해보자.
그러면 기존 상속에서는 메인 Class에서 새로운 자동차 종류 객체를 다루는 데 있어서 굉장히 많은 코드 수정이 필요하다.
이를 클린 하게 만들 수 있게 하는 게 다형성이다.
다형성의 특징 2가지에 대해 알아보자.
1. 다형적 참조 : 부모타입의 변수가 자식 인스턴스를 참조할 수 있다.
2. 메서드 오버라이드 : 오버라이드된 메서드가 "항상" 우선권을 가지며 최하위 자식의 메서드가 1순위이다.
(인스턴스 내에 있는 메서드만 해당)
다형성은 상속과 밀접한 관련이 있다.
상속은 자식 Class가 부모 Class의 요소를 상속받아 사용하는 방식이었다.
자바에서는 참조값을 통해 메모리 주소를 찾아간다.
Child 클래스가 Parent 클래스를 상속받는다고 가정해 보자.
main클래스에서 아래 코드와 같이 객체를 생성하면 힙영역 메모리는 어떻게 될까?
public class Main(){
public static void main(String[] args) {
Parent parent = new Parent();
Child child = new Child();
}
}
parent에서는 힙 영역에 parent의 참조값만 들어가게 될 것이고, child는 child와 parent의 참조값 모두가 들어간다.
이는 상속에서도 익힌 내용이다.
자 그렇다면 아래 코드는 어떻게 될까?
public class Main(){
public static void main(String[] args) {
Parent parent = new Child();
Child child = new Parent();
}
}
parent는 정상적으로 실행이 될 것이고, child는 컴파일 오류를 낼 것이다.
왜 그럴까?
일단 다형적 참조에 대해 다시 되새겨 보자.
다형적 참조 : 부모타입의 변수가 자식 인스턴스를 참조할 수 있다.
바로 다형적 참조 덕분에 parent는 정상적으로 컴파일된다.
또한 힙 영역에 Parent와 Child 객체 모두의 주솟값이 들어가게 된다.
그렇다면 Child 부분은 어떨까?
일단 코드대로 실행하게 된다면 컴파일 오류가 난다.
이를 해결하기 위해 다운 캐스팅을 진행해주어야 한다.
아래 코드를 참고하자
public class Main(){
public static void main(String[] args) {
Parent parent = new Child();
Parent child = (Child) parent;
}
}
바로 부모 객체 앞에 (Child)를 입력해 줌으로써 Parent객체를 Child 타입에 강제로 넣을 수 있게 된다.
이를 다운캐스팅이라고 한다.
주의사항!
parent 같이 자식객체를 넣게 되어서 힙 영역에 자식과 부모 모두의 참조값은 있지만, 자식 요소에 접근할 수가 없다.
그 이유는 바로 타입이 Parent이기 때문에 힙영역에서 Parent 타입부터 서치를 진행하게 된다.
우리는 과거에 힙 영역 상속관계 서칭은 자식에서 부모로 진행되며 역은 불가능하다는 것을 배웠다.
따라서 paret. 자식요소는 접근이 불가능하다.
이때 바로 다운캐스팅을 통해 접근할 수 있게 된다.
위와 같이 선언을 해주었을 경우에, 타입이 기존 Parent에서 Child로 변경된다.
우리 방금 뭐라고 했었는지 기억해야 한다.
"타입이 Parent이기 때문에 힙영역에서 Parent 타입부터 서치를 진행하게 된다."
다운 캐스팅을 통해 타입이 Child로 변했다.
따라서 child 변수는 이제 자식의 요소에 접근할 수 있게 되었다.
추가적으로
Parent parent = new Child();
이거는 업 캐스팅인데, 자바에서 업캐스팅은 문제가 없다.
따라서 생략한다.
궁금하다면, 상속관계 자식객체 생성 시 힙영역 참조값을 생각해 보면 된다. (자식 생성하면 자동으로 부모 만들어짐)
다운 캐스팅이 문제가 될 수 있는 이유는, 자식은 반드시 부모의 요소를 갖고 있지만, 부모는 자식의 요소가 없기 때문이다.
Tip
다운 캐스팅 선언 없이 일시적으로 자식의 요소를 사용할 수 있는 방법이 있다.
((Child) parent).childmethod();
연산자 우선순위 때문에, 괄호를 위와 같이 사용하였다.
이럴 경우에는 대입 연산자( = )를 사용한 것이 아니라 다운 캐스팅이 위 한 줄에 대해서만 유효하다.
instanceof에 대해서도 간단하게만 알아보자
A instanceof B
A의 타입이 B에 온전히 들어갈 수 있으면 true 아니면 false를 반환한다.
A가 자식이고, B가 부모객체면 Class면 true를 반환하고 역은 false를 반환한다.
코드 예시를 통해 보고 넘어가자
new Parent() instanceof Parent
Parent p = new Parent() // true
new Child() instanceof Parent
Parent p = new Parent(); // true
new Parent() instanceof Child
Child c = new Parent(); // false
new Child() instanceof Child
Child c = new Child(); // true
자 이제 다형성에 관한 코드를 보자.
Main 코드
public class PolyMain {
public static void main(String[] args) {
// 인터페이스 인스턴스 생성 불가
Cat cat = new Cat();
Dog dog = new Dog();
Cow cow = new Cow();
Animal[] animals = new Animal[]{cat, dog, cow};
for (Animal animal : animals) {
soundAnimal(animal);
}
}
private static void soundAnimal(Animal animal){
System.out.println("동물 소리 테스트 시작");
animal.sound();
System.out.println("동물 소리 테스트 끝");
}
}
부모 Animal Class
public class Animal {
public void sound(){
System.out.println("동물 소리");
}
public void move(){
System.out.println("동물 이동");
}
}
자식 Cat Class
public class Cat extends Animal {
@Override
public void sound() {
System.out.println("냐옹");
}
@Override
public void move() {
System.out.println("고양이 이동");
}
}
자식 Cow Class
public class Cow extends Animal {
@Override
public void sound() {
System.out.println("음메");
}
@Override
public void move() {
System.out.println("소 이동");
}
}
자식 Dog Class
public class Dog extends Animal {
@Override
public void sound(){
System.out.println("멍멍");
}
@Override
public void move(){
System.out.println("개 이동");
}
}
개, 소, 고양이 클래스는 Animal을 상속받으며, Animal의 메서드를 각 오버라이드 해서 자식에게 맞게끔 해주었다.
Main 클래스에서는 Animal 타입의 배열을 선언하여, 서로 다른 타입의 자식 객체들을 보관해 주었고 iterator를 통해
각 자식의 요소에 접근하는 것을 구현한 코드이다.
만약 다형성을 사용하지 않았더라면 for문을 통해 각 객체의 요소에 접근할 수 없으므로 추가될 코드가 많았을 것이다.
처음에 설명한 부분이 이 것이다.
다형성을 통해 우리는 for문에서 부모 객체 타입으로 통일시켜 각 자식 객체로 접근할 수 있게 만들었다.
'기술스택 > 자바(Spring)' 카테고리의 다른 글
자바 인터페이스(Interface) (0) | 2025.02.11 |
---|---|
자바 추상 클래스 (Abstract Class) (0) | 2025.02.11 |
자바 상속(Inheritance) (4) | 2025.02.09 |
자바 final (1) | 2025.02.08 |
자바 static (1) | 2025.02.08 |
- Total
- Today
- Yesterday
- 프로그래머스
- ys.k
- 프로그래머스 상품을 구매한 회원 비율 구하기
- 코딩테스트 준비
- 김영한
- Los
- samron
- 김영한 실전 자바 기초
- 스프링
- static
- los 15
- 백준
- lord of sql
- webhacking.kr
- los 15단계
- zixem
- 기술스택
- 상품을 구매한 회원 비율 구하기 파이썬
- spring
- java
- 백준 피보나치 수열
- 프로그래머스 상품을 구매한 회원 비율 구하기 파이썬
- 김영한 실전 자바 중급
- 코딩테스트
- 백준 피보나치
- samron3
- 상속
- 김영한 실전 자바 기본
- 자바
- extends
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |