본문 바로가기
Java/Java

객체 지향 3대 원칙) 다형성에 대하여, 업 캐스팅, 다운 캐스팅

by 박채니 2022. 3. 24.
SMALL

안녕하세요, 코린이의 코딩 학습기 채니 입니다.

 

개인 포스팅용으로 내용에 오류 및 잘못된 정보가 있을 수 있습니다.


다형성이란?

- 상속을 이용한 기술로, 자식 객체를 부모클래스타입의 변수로 다룰 수 있음

 

Animal 부모 클래스

public class Animal {
	public void say() {
		System.out.println("안녕하세요, 동물 입니다.");
	}
}

Lion 자식 클래스

public class Lion extends Animal {
	public void punch() {
		System.out.println("라이언 펀치!");
	}
}

Tiger 자식 클래스

public class Tiger extends Animal {
	public void kick() {
		System.out.println("타이거 킥!");
	}
}

메인 메소드

public class AnimalMain {
	public static void main(String[] args) {
		AnimalMain main = new AnimalMain();
		main.test1();
	}
	
	public void test1() {
		Lion lion = new Lion();
		lion.say();
		lion.punch();
		
		Tiger tiger = new Tiger();
		tiger.say();
		tiger.kick();
	}
}

@콘솔출력값
안녕하세요, 동물 입니다.
라이언 펀치!
안녕하세요, 동물 입니다.
타이거 킥!

다형성 적용 전의 코드입니다.

각 자식 클래스의 타입과 생성자를 이용하여 부모로부터 물려받은 say()메소드와 자식 클래스에서 정의한 punch(), kick()메소드를 실행하였습니다.

 

상속 구조

위와 같은 상속 구조를 띄고 있습니다.

 

상속 구조에서 자기 자신을 가리키거나 화살표 방향으로는 항상 다형적 표현을 할 수 있습니다.

'Animal은 Animal이다'를 코드로 표현하면 Animal animal = new Animal()이 되고,

'Lion은 Animal이다'를 코드로 표현하면 Animal animal = new Lion()이 되는 것이죠. 이것이 다형성 입니다.

 

그렇다면 다형성을 적용하면 어떻게 될까요?

public void test1() {
	Animal animal1 = new Lion();
	animal1.say();
//	animal1.punch();
		
	Animal animal2 = new Tiger();
	animal2.say();
//	animal2.kick();
}

@콘솔출력값
안녕하세요, 동물 입니다.
안녕하세요, 동물 입니다.

Animal 타입의 Lion()객체를 만들고 Animal 타입의 Tiger()객체를 만들었습니다.

그 후 메소드를 실행하려고 하니 자식 클래스에서 정의했던 punch()와 kick()은 사용 할 수 없고, 부모 클래스의 say() 메소드만 사용할 수 있었습니다.

 

그 이유는? (Lion객체로만 예를 들겠습니다.)

상속 시 객체 생성은 부모 클래스 객체 생성 후 자식 클래스 객체가 생성된다고 하였습니다.

따라서 위처럼 Lion객체 내에 Animal 객체가 생성된 것을 알 수 있고, 각 멤버를 갖고 있습니다.

하지만 Animal 타입으로 선언 되었기 때문에 실제 참조 변수는 힙 메모리의 Animal 객체를 가리키게 됩니다.

Animal 객체에는 Lion 객체만이 갖고 있는 punch()메소드를 갖고 있지 않기 때문에 메소드 사용이 불가했던 것입니다.

 

선언된 타입이 의미하는 바는 실제 객체에서 자신이 선언된 타입의 객체를 가리키게 되는 것입니다.

 

이런 경우, 자식 클래스의 메소드도 사용하고 싶을 땐 어떻게 하면 될까?

캐스팅을 이용하면 됩니다.


☞ 업 캐스팅 (up-casting)

- 자식 클래스에서 부모 클래스 쪽으로 변환 되는 것

- 객체는 항상 업캐스팅이 가능하므로 컴파일러가 대신 수행

public void test1() {
	Lion lion = new Lion();
	Animal animal1 = lion;	//업캐스팅
	animal.say();
		
	Animal animal2 = new Tiger();	//업캐스팅
	animal2.say();
}

@콘솔출력값
안녕하세요, 동물 입니다.
안녕하세요, 동물 입니다.

위 코드는 업 캐스팅이 수행된 코드입니다.

캐스팅 가능 여부는 어떤 생성자로 생성되었는 지가 중요합니다.

 

 

☞ 다운 캐스팅(down-casting)

- 부모 클래스에서 자식 클래스 쪽으로 변환 되는 것

- 자동이 아니므로 직접 명시적으로 수행해줘야 함

public void test1() {
		Animal animal1 = new Lion();
		Lion lionAgain = (Lion)animal1;	//다운캐스팅
		lionAgain.say();
		lionAgain.punch();
		
		Animal animal2 = new Tiger();
		Tiger tigerAgain = (Tiger)animal2;	//다운캐스팅
		tigerAgain.say();
		tigerAgain.kick();
	}
}

@콘솔출력값
안녕하세요, 동물 입니다.
라이언 펀치!
안녕하세요, 동물 입니다.
타이거 킥!

 

메모리 상으로 본다면 위와 같을 것입니다.

Animal 타입의 animal1은 Animal 객체를 가리키기 때문에 say()메소드만 호출할 수 있었다면,

Lion lionAgain = (Lion)animal1은 Animal 타입의 animal1을 Lion 타입으로 캐스팅하여 Lion 타입으로 저장하려고 합니다.

따라서 Lion 객체를 가리키게 되어 say()와 punch() 메소드를 사용할 수 있는 것이죠.

 

바로 메소드로 호출하고 싶다면 아래처럼 다운캐스팅을 바로 수행하여 메소드 호출도 할 수 있습니다.

((Lion)animal1).punch();

 

LIST