본문 바로가기
My Image
프로그래밍/Java

[Java] 타입 변환과 필드의 다형성

by Lim-Ky 2017. 8. 22.
반응형

안녕하세요 Limky 입니다.

이번 시간은 객체지향에서 정말 중요한 "다형성"에 대해서 알아보겠습니다.


다형성은 같은 타입이지만 실행 결과가 다른 것을 뜻합니다.

즉 동일한 타입에 다양한 객체를 이용하여 다양한 결과를 만들 수 있습니다.

이런 다양성을 지원하기 위해 자바에서는 부모 클래스 타입에 모든 자식 객체가 대입 될 수 있도록 자동 타입 변환을 시켜줍니다.


자동 타입 변환은 부모 클래스를 상속받은 자식클래스들의 타입을 부모 클래스 타입인 변수가 대입 받을 수 있습니다.


부모클래스 타입 변수 = new 자식클래스();


이 과정에서 자바는 자동적으로 부모클래스 타입의 변수가 자식클래스 타입의 인스턴스를 대입 받을 수 있도록 명시적으로 타입변환을 선언하지 않아도 내부적으로 타입변환을 시켜줍니다. 



예를 들어 Animal 부모클래스를 상속받은 Cat 클래스의 인스턴스는 굳이 Cat 클래스 타입이 아니여도 상속 관계에 있는 부모클래스 타입의 변수라면, 대입 될 수 있습니다.

Animal animal = cat; 이 줄에서 자동적으로 타입 변환이 발생합니다.

그 관계를 JVM 메모리에선 어떻게 참조되는 지 위 그림에서 확인 할 수 있습니다.


이렇게 자동 타입 변환이 발생하여 자식클래스의 인스턴스를 대입 받은 부모클래스 타입의 변수는 몇 가지 특징을 가집니다. 


1. 부모클래스에 선언된 필드와 메소드만 접근이 가능합니다.

    -> 비록 변수는 자식 인스턴스를 참조하지만, 변수로 접근 가능한 멤버는 부모클래스 멤버로만 한정됩니다.

2. 만약 부모클래스 메서드를 자식클래스에서 오버라이딩 한 경우라면, 자식클래스 메서드가 대신 호출됩니다. 


이 2가지 특징 중에 가장 중요한 것이 바로 2번 입니다. 

부모클래스에서 미리 정의한 메서드 중에서 자식클래스가 오버라이딩하여 재정의 한 메서드가 대신 호출되는 것이야 말로 다형성의 효과를 극대화 할 수 있습니다.


예제를 보면서 필드의 다형성에 대해 더 알아보겠습니다.

해당 예제는 "이것이 자바다" 에서 발췌 했습니다.


Tire.java

package JavaDiversityExample;

public class Tire {

	//필드
	public int maxRotation; 		//최대 회전수 (타이어 수명)
	public int accmulatedRotation; 	//누적 회전수
	public String location;			//타이어의 위치
	
	//생성자
	public Tire(String location, int maxRotation) {
		//필드 초기화
		this.location = location;
		this.maxRotation = maxRotation;
	}
	
	//메서드
	public boolean roll() {
		
		++accmulatedRotation;//누적 회전수를 증가시킨다.
		
		//누적회전수가 타이어의 최대회전수보다 많아지는 경우 타이어는 펑크난다.
		if(accmulatedRotation < maxRotation) {
			System.out.println(location + "Tire 수명 : " + (maxRotation - accmulatedRotation) + "회");
			return true;
			
		}else {
			System.out.println("*** " + location + "Tire 펑크 ***");
			return false;
		}
	}
	
}


Car.java
package JavaDiversityExample;

public class Car {
	
	//필드
	Tire frontLeftTire = new Tire("앞 왼쪽", 6);
	Tire frontRightTire = new Tire("앞 오른쪽", 2);
	Tire backLeftTire = new Tire("뒤 왼쪽", 3);
	Tire backRightTire = new Tire("뒤 오른쪽", 4);
	
	//기본 생성자
	
	//메서드
	int run() {
		System.out.println(">>> 자동차가 달립니다. >>>");
		if(!frontLeftTire.roll()) {stop(); return 1;}
		if(!frontRightTire.roll()) {stop(); return 2;}
		if(!backLeftTire.roll()) {stop(); return 3;}
		if(!backRightTire.roll()) {stop(); return 4;}
		return 0;
	}
	
	void stop() {
		System.out.println("xxx 자동차가 멈춥니다. xxx");
		
	}
}

HanKooKTire.java

package JavaDiversityExample;

import javax.jws.soap.SOAPBinding;

public class HanKooKTire extends Tire{

	public HanKooKTire(String location, int maxRotation) {
		super(location, maxRotation);
		// TODO Auto-generated constructor stub
	}

	//메소드
	/** tire의 roll() 메서드 재정의 구현 **/
	@Override
	public boolean roll() {
		++accmulatedRotation;
		if(accmulatedRotation < maxRotation) {
			System.out.println(location + " HanKooKTire 수명 : " + (maxRotation - accmulatedRotation) + "회");
			return true;
		}else {
			System.out.println("*** "+ location +" HanKooKTire 평크 ***");
			return false;
		}
	}
	
}


KumhoTire.java

package JavaDiversityExample;

public class KumhoTire extends Tire {

	public KumhoTire(String location, int maxRotation) {
		super(location, maxRotation);
		// TODO Auto-generated constructor stub
	}

	//메소드
	/** tire의 roll() 메서드 재정의 구현 **/
		@Override
		public boolean roll() {
			++accmulatedRotation;
			if(accmulatedRotation < maxRotation) {
				System.out.println(location + " KumhoTire 수명 : " + (maxRotation - accmulatedRotation) + "회");
				return true;
			}else {
				System.out.println("*** "+ location +" KumhoTire 평크 ***");
				return false;
			}
		}
}


CarExample.java

package JavaDiversityExample;

public class CarExample {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Car car = new Car();
		
		for(int i=1; i<=5; i++) {
			int problemLocation = car.run();
		
			switch (problemLocation) {
			case 1:
				System.out.println("앞 왼쪽 HanKooKTire로 교체");
				car.frontLeftTire = new HanKooKTire("앞 왼쪽 ", 15);
				
				break;
			case 2:
				System.out.println("앞 오른쪽 KumhoTire로 교체");
				car.frontRightTire = new KumhoTire("앞 오른쪽 ", 13);
				
				break;
			case 3:
				System.out.println("뒤 왼쪽 HanKooKTire로 교체");
				car.backLeftTire = new HanKooKTire("뒤 왼쪽 ", 14);
				
				break;
			case 4:
				System.out.println("뒤 오른쪽  KumhoTire로 교체");
				car.backRightTire = new KumhoTire("뒤 오른쪽 ", 17);
				
				break;

			default:
				
				break;
			}
			System.out.println("=================" + i + " 회전 =================");
		}
	}

}


 결과


>>> 자동차가 달립니다. >>>

앞 왼쪽Tire 수명 : 5회

앞 오른쪽Tire 수명 : 1회

뒤 왼쪽Tire 수명 : 2회

뒤 오른쪽Tire 수명 : 3회

=================1 회전 =================

>>> 자동차가 달립니다. >>>

앞 왼쪽Tire 수명 : 4회

*** 앞 오른쪽Tire 펑크 ***

xxx 자동차가 멈춥니다. xxx

앞 오른쪽 KumhoTire로 교체

=================2 회전 =================

>>> 자동차가 달립니다. >>>

앞 왼쪽Tire 수명 : 3회

앞 오른쪽  KumhoTire 수명 : 12회

뒤 왼쪽Tire 수명 : 1회

뒤 오른쪽Tire 수명 : 2회

=================3 회전 =================

>>> 자동차가 달립니다. >>>

앞 왼쪽Tire 수명 : 2회

앞 오른쪽  KumhoTire 수명 : 11회

*** 뒤 왼쪽Tire 펑크 ***

xxx 자동차가 멈춥니다. xxx

뒤 왼쪽 HanKooKTire로 교체

=================4 회전 =================

>>> 자동차가 달립니다. >>>

앞 왼쪽Tire 수명 : 1회

앞 오른쪽  KumhoTire 수명 : 10회

뒤 왼쪽  HanKooKTire 수명 : 13회

뒤 오른쪽Tire 수명 : 1회

=================5 회전 =================



Tire의 수명이 다 되기 전에는 기존에 있는 Tire의 roll() 메서드가 동작하지만,

타이어의 수명이 다 되면 Tire 타입에 Tire를 상속받은 KumhoTire, HanKooKTire클래스 인스턴스로 교체 시킵니다. 즉 부모클래스 Tire의 타입에 자식클래스 인스턴스를 대입 받는 것이지요.

이제 교체된 Tire에선 새로 대입 된 자식클래스 roll() 메서드가 동작합니다.

KumhoTire, HanKooKTire 클래스가 roll() 메서드를 오버라이딩해서 각자의 입맛에 맞게 재정의 했기 때문에 더 이상 부모클래스의 roll() 메서드가 동작하지 않고 재정의된 roll() 메서드가 호출되는 것이지요. 이것이 바로 필드의 다형성입니다. 


다형성은 객체지향에서도 정말 중요한 개념입니다.

실무에서도 확장 가능하면서 다양한 결과를 내야할 때 반드시 다형성을 이용해야 합니다. 그렇지 않으면 유지보수는 과정이 너무 힘들기 때문이죠...


만약 A사의 카메라와 연동하여 셀카를 찍을 수 있는 안드로이드 앱을 개발 했다고 칩시다. 이 앱은 무조건 A사의 카메라만 연동이 가능하기 때문에 B사의 카메라와 연동하는 앱을 만들기 위해선 처음부터 다시 설계하고 개발 해야 합니다. 또한 이 제품을 가지고 영업을 할 때도 불리합니다.

왜냐면 우리는 A사 카메라가 아니고선 서비스가 되지 않습니다. 라는 말이거든요....

만약 확장 가능한 설계를 했다면, 우리 제품은 카메라 SDK만 지원한다면 어떤 카메라와도 연동할 수 있는 앱 입니다. 라고 영업할 수 있습니다. 느낌이 확 오시나요..? 그 만큼 다형성은 실무에서 더욱 중요한 개념이기에 꼭 곱씹으면서 완벽하게 알아둬야 합니다.


다음 시간에는 매개 변수의 다형성, 강제 타입 변환, 추상클래스 등에 대해서 알아보도록 하겠습니다.











반응형

댓글