Java - 클래스 형변환과 장점

컴퓨터/Java

728x90
반응형

먼저 기억하자

지난 포스트들에서 클래스와 클래스들을 다루는 다양한 방법에 대하여 계속해서 알아보고 있습니다. 이런 개념들이 계속해서 확장되는 장점이 생기기 때문입니다. 이 장점 중 하나를 이번 포스트에서 말해보려고 합니다.

그전에 아래 내용에 대해 개념이 부족하다면 조금 더 공부해보고 오시길 권장합니다.

  • 클래스의 개념
  • 오버라이드 / 오버 라이딩 / 생성자 / 상속
  • 추상 클래스와 인터페이스

클래스의 형변환 준비

클래스 또한 하나의 자료형입니다. 따라서 형 변환이 가능하게 됩니다. 상속관계의 클래스들로 형 변환이 가능합니다. 

예제를 통해 하나 클래스들의 형변환을 알아보도록 하겠습니다.

 

  • 부모 클래스 Human
/* 상위(부모) 클래스 Human */
public class Human {
	
	// 맴버 변수 (상속하기 위해 priotected)
	protected String color;
	// 멤버 메서드
	public void say(){
		System.out.println("저는 사람입니다.");
	}
	public void sayColor() {
		System.out.println("저의 피부색은 "+color+"입니다.");
	}
	//생성자
	Human(){};
}

 

  • Human을 상속받은 Man클래스
public class Man extends Human{
	
	// 멤버 변수
	private String name;

	// 멤버 메서드
	public void mansay() {
		System.out.println("저는 남자이며 이름은 "+name+"입니다.");
	}
	
	// 상위 클래스의 오버라이드
	public void say() {
		System.out.println("저는 사람이고 남자입니다.");
	}
	
	// 생성자 정의
	public Man(String name, String color) {
		this.name = name;
		this.color = color;
	}
}

 

  • Human을 상속받은 Woman클래스
public class Woman extends Human{

	// 멤버 변수
	private String name;

	// 멤버 메서드
	public void womansay() {
		System.out.println("저는 여자이며 이름은 "+name+"입니다.");
	}
	
	// 상위 클래스의 오버라이드
	public void say() {
		System.out.println("저는 사람이고 여자입니다.");
	}
	
	// 생성자 정의
	public Woman(String name, String color) {
		this.name = name;
		this.color = color;
	}
}

 

위의 선언된 소스코드를  정리하자면 다음과 같습니다.

  • Human 클래스의 메서드는 2개가 있다.
  • 상속받은 각각의 클래스들은 하나의 Human 새롭게 정의된 1개의 메서드와 상속받은 클래스의 1개의 메서드를 오버라이드 했다.

이제 Test를 위해 콘솔창을 이용해서 각각의 클래스들의 객체화하고 테스트하는 환경의 소스코드를 만들어 보도록 하겠습니다.

public class Test {

	public static void main(String[] args) {

		Human h ;
		Man m = new Man("김민수","황색");
		Woman w = new Woman("애니","흰색");
		
		// 인스턴스 m 과 w 가 가진 각각의 메서드를 실행 
		m.mansay();   // 고유 메서드
		m.say();	  // 상속 메서드의 오버라이드 메서드
		m.sayColor(); // 상속받은 메서드
		
		w.womansay();
		w.say();
		w.sayColor();
	}
}

결과는 아래와 같습니다.

형변환을 해보고 동작을 해보자

이제 만들어진 예제 클래스들을 통하여 형 변환을 해보도록 하겠습니다.

 

  • 부모 클래스로 형 변환해보기(업 케스팅)

부모 클래스를 이용하여 형변환을 하는 방법은 인스턴스화 하지 않은 부모 클래스 자료형의 변수에 대입을 해주면 됩니다.

public class Test {

	public static void main(String[] args) {

		Human h ;
		Man m = new Man("김민수","황색");
		Woman w = new Woman("애니","흰색");

		// 부모 클래스로 형변환 해보기
		h = (Human)m;
		h = w;
	}
}

미리 만들어 둔 h라는 Human 클래스 자료형 변수에 자식클래스로 만든 인스턴스 m과 w를 형 변환해 봤습니다.

w를 형변환 한 것처럼 상위 클래스로  형 변환을 하기 위해서는 형 변환을 위한 명시적 표현을 생략 가능합니다. 

(그래도 가능한 명시적 표현을 하는 것을 권장합니다.)

 

  • 부모클래스로 형 변환이 된 인스턴스의 메서드를 호출해 보자

부모클래스로 형 변환된 각각의 하위 클래스로 만들어진 인스턴스들은 부모 클래스와 다른 메서드들이 하나씩 있습니다. 그리고 오버라이드 된 메서드도 존재합니다. 과연 이 메서드들이 부모 클래스로 형 변환이 되면 어떻게 사용되는지 알아보도록 하겠습니다.

public class Test {

	public static void main(String[] args) {

		Human h ;
		Man m = new Man("김민수","황색");
		Woman w = new Woman("애니","흰색");
		
		// 부모 클래스로 형변환 해보기
		// h = (Human)m;
		// 두 클래스다 동일함으로 Woman인 w를 활용 해 보도록 하겠습니다.
		h = w;
		// h.womansay(); 에러 발생
		h.say();
		h.sayColor();
	}
}

위 소스코드의 결과를 가지고 자식클래스는 상위 클래스로 형 변환이 가능하지만 몇 가지 특징이 있다는 것을 확인할 수 있습니다.

  1. 상위 클래스에 존재하지 않는 메서드는 사용할수 없다.
  2. 오버라이드 된 메서드는 오버라이드 된 상태 그대로 계속 적용이 된다. (상위 클래스의 원본을 사용하지 않는다)

이처럼 상위클래스로 형 변환을 하는 것을 Java에서는 업 캐스팅이라고 말합니다.

 

  • 상위 클래스가 아닌 동일 클래스의 형변환은 가능할까?

우선 결론은 불가능합니다. 불가능을 설명하기 위해서 아래 도식을  보며 이해해보도록 합시다.

업 케스팅이 가능한 이유는 우리가 만든 Man 클래스는 Human 클래스의 일부분을 상속받는 것을 이미 정의해 두었기 때문에 공통된 부분을 알 수 있어 형 변환이 가능합니다. 하지만 Man과 Woman의 경우 둘의 관계가 상속인지, 공통돼있는지 알 수 없기 때문에 형 변환이 불가능합니다.

 

  • 업 캐스팅 된 클래스를 다시 돌려보기 (다운 케스팅)

이제 우리는 업 캐스팅을 한 클래스를 다시 원래의 클래스 즉 하위의 클래스로 돌아와 보는 형 변환을 해보도록 하겠습니다. 이를 다운 캐스팅이라고 하며 사용 방법은 아래와 같습니다.

public class Test {

	public static void main(String[] args) {

		Human h ;
		Man m = new Man("김민수","황색");
		Woman w = new Woman("애니","흰색");
		// 부모 클래스로 형변환 해보기
		// h = (Human)m;
		// 두 클래스다 동일함으로 Woman인 w를 활용 해 보도록 하겠습니다.
		h = w;
        // 다시 Woman 클래스로 다운 케스팅 해보기
		Woman w2;
		// w2 = h; 에러 발생
		w2 = (Woman)h;
		w2.womansay();
	}
}

이처럼 다시 본래 모두의 기능을 하도록 다운케스팅을 하는 방법을 알아보았습니다. 다만 다운 캐스팅을 할 때에는 항상 명시적 형 변환이 이루어져야 된다는 것을 확인할 수 있습니다.  그 이유는 상위 클래스가 상속을 하는 클래스는 하나가 아닌 여러 개이기 때문입니다. 

 

그렇다면 만약 업 케스팅된 Woman 인스턴스를 Man으로 다운 캐스팅을 하는 것은 가능한지 알아볼까요?

public class Test {

	public static void main(String[] args) {

		Human h ;
		Man m = new Man("김민수","황색");
		Woman w = new Woman("애니","흰색");
		// 부모 클래스로 형변환 해보기
		// h = (Human)m;
		// 두 클래스다 동일함으로 Woman인 w를 활용 해 보도록 하겠습니다.
		h = w;
        // 다시 Woman 클래스로 다운 케스팅 해보기
		//케스팅된 Woman 클래스를 Man으로 형변환 해보자.
		Man m2;
		//m2 = h;
		m2 = (Man)h;
		m2.mansay();
	}
}

일단.. Human 클래스의 데이 터니까 받아 옵니다. 하지만 mansay 메서드의 경우 받아온 h에는 존재하지 않는 값이기 때문에 다음과 같이 에러가 발생합니다.

그렇다면 다시 원래의 클래스로 돌아오기 위해서 어떻게 해야 되는지 알아보도록 하겠습니다.

 

  • instanceof 사용해보기 

Java에서 제공하는 instanceof 키워드를 사용하면 변수 안에 들어 있는 인스턴스를 확인해 볼 수 있습니다.

 

public class Test {

	public static void main(String[] args) {

		Human h ;
		Man m = new Man("김민수","황색");
		Woman w = new Woman("애니","흰색");
		// 부모 클래스로 형변환 해보기
		// h = (Human)m;
		// 두 클래스다 동일함으로 Woman인 w를 활용 해 보도록 하겠습니다.
		h = w;
        // 다시 Woman 클래스로 다운 케스팅 해보기
		// instanceof를 확인해 봅시다.
		System.out.println("변수 h의 들어 있는 녀석은 Man타입인가?" + (h instanceof Man));
		System.out.println("변수 h의 들어 있는 녀석은 Woman타입인가?" + (h instanceof Woman));
	}
}

위의 결괏값처럼 정확한 다운 캐스팅을 하기 위해 해당 키워드를 사용할 수 있다.

본문에서 지금까지 클래스 형 변환에 대한 말을 계속해서 말하고 있는데 왜 사용하는지에 대해서 설명을 이제 해보도록 하겠습니다.

 

클래스 형 변환을 사용하는 이유와 장점

만약 프로그래밍을 하는 과정에서 Man과 Woman을 가지고 인스턴스를 각각 생성하여 따로 관리한다면 불편할 것입니다. 그래서 이전 포스트에서 클래스 배열을 통해서 통합적으로 관리하는 방법에 대해서 알아보았습니다. 하지만 경우에 따라서 Man과 Woman으로 만든 인스턴스들을 한 배열에서 통합적으로 관리하기 위해서는 어떻게 해야 될까요? 

이때 바로 업 캐스팅 형 변환을 이용하면 하나의 배열의 형태로 사용할 수 있게 됩니다.

public class Test {

	public static void main(String[] args) {

		Human[] h = new Human[2];
		Man m = new Man("김민수","황색");
		Woman w = new Woman("애니","흰색");
		h[0] = (Human)m;
		h[1] = (Human)m;
		
		//처음부터 선언하기
		Human[] h2 = new Human[2];
		h2[0] = new Man("스미스","검은색");
		h2[1] = new Woman("이익순","흰색");

	}
}

 

다시 원래로 돌아오는 다운 케스팅 구현해보기 

만약 다시 꺼내서 원래 클래스의 기능을 꺼내 쓰고 싶다면 다운 테스팅을 해야만 가능합니다. 

위에서 배운 instanceof 키워드를 사용하여 정확한 다운케스팅을 구현해 볼 수 있습니다.

public class Test {

	public static void main(String[] args) {

		Human[] h = new Human[2];
		Man m = new Man("김민수","황색");
		Woman w = new Woman("애니","흰색");
		h[0] = (Human)m;
		h[1] = (Human)m;
		
		//처음부터 선언하기
		Human[] h2 = new Human[2];
		h2[0] = new Man("스미스","검은색");
		h2[1] = new Woman("이익순","흰색");

		if(h2[0] instanceof Woman) {
			Woman temp = (Woman)h2[0];
			temp.womansay();
		}
		else if(h2[0] instanceof Man) {
			Man temp = (Man)h2[0];
			temp.mansay();
		}
	}
}

 

본 포스트를 통해 다운 캐스팅과 업 캐스팅에 대한 이해로 Java에서 다양한 클래스들을 효율적으로 활용할 수 있도록 기원합니다.

728x90
반응형

'컴퓨터 > Java' 카테고리의 다른 글

Java - 컬렉션프레임워크(CKP)  (0) 2021.10.05
Java - for each문  (0) 2021.09.09
Java - 인터페이스(Interface)  (0) 2021.08.19
Java - 추상화 클래스  (0) 2021.08.15
Java - Get/Set 함수에 익숙해지자  (0) 2021.08.13

Commnet

G91개발일지

Gon91(지구일)

91년생 공학엔지니어의 개발일지

TODAY :

YESTER DAY :

TOTAL :