야미의 개발

[JAVA] 다형성 - 캐스팅과 메소드오버라이딩 본문

JAVA

[JAVA] 다형성 - 캐스팅과 메소드오버라이딩

채야미 2024. 1. 31. 11:40

출처 

https://www.inflearn.com/course/%EA%B9%80%EC%98%81%ED%95%9C%EC%9D%98-%EC%8B%A4%EC%A0%84-%EC%9E%90%EB%B0%94-%EA%B8%B0%EB%B3%B8%ED%8E%B8/dashboard

 

김영한의 실전 자바 - 기본편 강의 - 인프런

실무에 필요한 자바 객체 지향의 핵심 개념을 예제 코드를 통해 쉽게 학습합니다., 국내 개발 분야 누적 수강생 1위, 제대로 만든 김영한의 실전 자바[사진][임베딩 영상]단순히 자바 문법을 안다

www.inflearn.com

 

본 내용은 김영한님의 실전 자바 강의를 보고 정리한 내용입니다 자세한 내용은 강의를 참고해주세요!

 

 

다형성

객체 지향 프로그래밍에서

다형성(Polymorphism)은 객체 지향의 주요 개념 중 하나로,

프로그램 언어의 각 요소들이 다양한 자료형에 속하는 것이 허가되는 성질

-> 하나의 타입에 여러 객체를 대입할 수 있는 성질입니다

 

 

Java에서의 다형성을 나타내는 개념에는

오버라이딩, 오버로딩, 상속받는 객체의 참조변수 형변환 등이 있습니다

그리고 다형성을 이해하기 위해서는 아래의 두가지 개념에 대해 알아보겠습니다. 

  • 다형성 참조
  • 메소드 오버라이딩

 

 

다형적 참조

package poly.basic;
//부모 객체
public class Parent {
 	public void parentMethod() {
		System.out.println("Parent.parentMethod");
 	}
}

package poly.basic;
//부모객체를 상속받는 자식 객체
public class Child extends Parent {
	public void childMethod() {
 		System.out.println("Child.childMethod");
	}
}

 

위와같은 클래스들이 있다고 가정할 때 아래의 변수에 객체를 대입하는 상황들을 먼저 보면


1. 부모 변수가 부모 인스턴스 참조

Parent parent = new Parent();

 

2. 자식 변수가 자식 인스턴스 참조

Child child = new Child();

 

3. 부모 변수가 자식 인스턴스 참조(다형적 참조)

Parent poly = new Child();

 

위와 같이 3가지 참조가 가능합니다

 

 위는 3번째 다형적 참조의 메모리 구조입니다.

부모타입의 변수가 자식 인스턴스를 참조합니다

Child 인스턴스를 만들때에는 메모리 상에 Child와 Parent 모두 생성됩니다. 

Parent poly = new Child();

 --> poly.parentMethod();

따라서 위와 같은 상황에서 

poly는 Parent 타입이므로 Parent 클래스부터 시작하여 메소드인 parentMethod를 찾고 

호출될 수 있습니다. 

 

한편 

poly는 Parent 타입이므로 Parent 클래스부터 기능을 찾고, 상속관계에서는 자식방향으로 내려갈 수 없습니다. 따라서 Child 객체안에 있는 childMethod는 호출할 수 없습니다 

-> 이럴때 캐스팅(형변환)이 필요합니다.

 

 

캐스팅(형변환)

위의 상황에서 poly를 Parent 타입이 아닌 Child 타입으로 변경한다면 Child에 있는 childMethod를 호출할 수 있습니다.

Child child = (Child) poly //Parent poly;

다음과 같이 괄호 사이에 그 타입을 지정하면 참조 대상을 특정 타입으로 변경할 수 있고

이것을 캐스팅(형변환)이라 합니다. 

chlid 객체는 타입이 자식타입이므로 childMethod를 호출 할 수 있습니다.

(poly의 타입이 바뀌는 것은 아님)

 

 

캐스팅의 종류

  • 업캐스팅(upcasting): 부모 타입으로 변경
  • 다운캐스팅(downcasting): 자식 타입으로 변경

 

다운캐스팅

Child child = (Child) poly //Parent poly;

부모 타입의 poly를 자식 타입으로 변경했으니 위의 코드는 다운 캐스팅입니다.

 

업캐스팅

Child child = new Child();
Parent parent1 = (Parent) child;

Child 타입을 Parent 타입에 대입해야 한다. 따라서 타입을 변환하는 캐스팅이 필요합니다. 

 

한편 다운캐스팅과 달리 부모는 자식을 담을 수 있기때문에 위와같은 업캐스팅은 생략이 가능합니다.

 

그렇다면 다운캐스팅만 명시적으로 적어야하는 이유는 무엇일까?

 

 

다운캐스팅과 주의점

다운캐스팅을 잘못했을 경우 런타임 오류가 발생할 수 있습니다. 

package poly.basic;
//다운캐스팅을 자동으로 하지 않는 이유
public class CastingMain4 {
	public static void main(String[] args) {
    
 		Parent parent1 = new Child();
 		Child child1 = (Child) parent1;
 		child1.childMethod(); //문제 없음
        
 		Parent parent2 = new Parent();
 		Child child2 = (Child) parent2; //런타임 오류 - ClassCastException
 		child2.childMethod(); //실행 불가
 	}
}

 

위의 상황에서 child2는 처음에 Parent타입으로 객체를 생성하기 때문에

메모리 상에 자식 타입은 존재하지 않습니다 

따라서 (Child)를 사용하여 형변환을 하고나서 사용할 Child가 메모리에 존재하지 않고

childMethod를 호출하기도전에

다운 캐스팅을 할 때 ClassCastException라는 예외가 발생됩니다. 

 

 

instanceof

다형성에서는 참조형 변수는 다양한 자식을 대상으로 참조할 수 있습니다. 

따라서 참조하는 대상이 다양하므로 어떤 인스턴스를 참조하고 있는지 확인하고 싶을때

바로 instanceof 키워드를 통해 확인 할 수 있습니다.

 

	public static void main(String[] args) {
	 	Parent parent1 = new Parent();
		System.out.println("parent1 호출");
	 	call(parent1);
 		Parent parent2 = new Child();
 		System.out.println("parent2 호출");
		call(parent2);
 	}
    
 	private static void call(Parent parent) {
 		parent.parentMethod();
 		if (parent instanceof Child) {
	 		System.out.println("Child 인스턴스 맞음");
	 		Child child = (Child) parent;
		 	child.childMethod();
 		}
 	}

 

위의 코드와 같이 Parent의 타입으로 넘어온 변수를 instanceof 로 확인하여 원하는 타입으로 변경이 가능한지 확인한후 다운캐스팅을 수행할 수 있습니다. 

이를 통해 다운캐스팅을 하다 메모리 상에 인스턴스가 없어 런타임에러가 발생하는 것을 막을 수 있습니다. 

 

 

 

메서드 오버라이딩

메서드 오버라이딩에서는 오버라이딩 된 메서드가 항상 우선권을 가집니다. 

 

따라서 

Parent poly = new Child();

다음과 같이 부모 타입으로 만들어진 poly 변수가 있을때

poly는 기본적으로 부모타입에 있는 메소드를 먼저 사용하지만,

오버라이딩된 메소드가 있을때에는 무조건 자식타입에 있는 메소드를 호출하게 됩니다

 

위과 같은 그림으로 이해할 수 있습니다. 

Comments