[Java] #26 상속 4 (참조자료형 형변환 및 다형성)

febCho·2024년 1월 3일
0

Java

목록 보기
49/53

앞서 배운 것처럼 상속 관계에 있는 객체의 자료형은 자식 클래스의 클래스명을 참조자료형으로 사용하게 된다.
ex. 클래스 A (a()) → 클래스 B 상속 A (b()) → 자식 클래스 B 객체 Bc 생성 → 상속 관계에 있는 객체의 메서드 호출시 자식 클래스명 사용 : Bc.a();
참고) 상속 1 (개념)

이때, 자료형을 자식 클래스명 대신 부모 클래스명으로 변경할 수 있다. 우리는 이를 참조자료형 형변환이라고 하며, 이를 통해 우리는 다형성(Polymorphism)을 구현할 수 있게 된다.
다형성은 한 객체가 여러 모습을 가질 수 있다는 것을 의미하는데, 자바 언어 측면에서 살펴보면 한 객체가 여러 타입이 될 수 있다는 것을 의미한다. 또한, 다형성 측면에서 참조자료형이 일종의 호출 범위 역할을 한다는 것을 알 수 있다.
단, 자식 클래스 객체가 생성된 후 부모 클래스의 자료형을 사용하면 호출할 수 있는 범위가 부모 클래스의 멤버변수, 멤버메서드로 한정된다.

예제를 통해 자세히 알아보자.

4. 참조자료형 형변환

4-1. 변수

package kr.s24.object2.poly;

//부모 클래스
class Parent{
	int a = 100;	
}

//자식 클래스
class Child extends Parent{
	int b = 200;
}

public class PolyMain01 {
	public static void main(String[] args) {
		Child ch = new Child();
		System.out.println(ch.a);
		System.out.println(ch.b);
		
		//업캐스팅
		Parent p = ch;
		System.out.println(p.a);
		//System.out.println(p.b);
		
		//다운캐스팅
		Child ch2 = (Child)p;
		System.out.println(ch2.a);
		System.out.println(ch2.b);
	}
}
  1. Parent 클래스를 상속받은 Child 클래스의 객체를 생성, 여태껏 배웠던 '상속' 문법대로 a() 메서드와 b() 메서드 모두를 '자식 클래스명을 참조자료형으로 사용'하여 호출하였다.

  2. 형변환 중 자식 > 부모 자동 형변환을 업캐스팅이라고 한다.
    업캐스팅 : 자식 클래스 타입에서 부모 클래스 타입으로 자동 형변환 되는 것
    ex. Parent p = ch; : ch 안에 child 객체를 가리키는 주소가 있고, 이를 p에 복사(저장)

  3. 이렇게 자식 클래스 객체가 생성된 후 부모 타입으로 업캐스팅 시, 부모 클래스 타입의 호출 범위난 경우에는 호출이 불가하다. 따라서 자식 클래스의 멤버변수는 부모 클래스명을 참조자료형으로 하여 호출할 수 없다.
    ex. //System.out.println(p.b);

  4. 예제 코드와 같이 부모 > 자식 명시적 형변환한 경우를 다운캐스팅이라고 한다.
    다운캐스팅 : 부모 클래스 타입에서 자식 클래스 타입으로 명시적 형변환 되는 것
    ex. Child ch2 = (Child)p; : p가 가지고 있는 주소를 ch2로 복사(저장)

  5. 다운캐스팅 시, 캐스팅 연산자를 활용해 명시적으로 형변환을 해주어야 한다. (업캐스팅) 보다 넓은 범위에서 좁은 범위로 자동 변환되었던 것과 달리, (다운캐스팅) 줄어들었던 범위를 강제로 늘려야 하기 때문에 자료형을 명시해준다고 생각하면 쉽다.
    ex. 캐스팅 연산자 : (Child)

4-2. 메서드

package kr.s24.object2.poly;

//부모 클래스
class A{
	public void make() {
		System.out.println("make 메서드");
	}
}

//자식 클래스
class B extends A{
	public void play() {
		System.out.println("play 메서드");
	}
}
public class PolyMain02 {
	public static void main(String[] args) {
		B bp = new B();
		bp.make();
		bp.play();
		
		//업캐스팅: 자식 > 부모 자동 형변환
		A ap = bp;
		ap.make();
		//ap.play();
		
		//다운캐스팅: 부모 > 자식 명시적 형변환
		B bp2 = (B)ap;
		bp2.make();
		bp2.play();
	}
}
  1. 메서드 역시 업캐스팅 후에는 부모 클래스명을 참조 자료형으로 하여 호출할 수 없다.
    ex. //ap.play();

  2. 그리고 다운캐스팅 시에는 캐스팅 연산자를 활용한 명시적 형변환이 필요하다.
    ex. B bp2 = (B)ap;

4-3. 메서드 오버라이딩

package kr.s24.object2.poly;

//부모 클래스
class Parent2{
	public void make() {
		System.out.println("부모클래스의 make");
	}
}

//자식 클래스
class Child2 extends Parent2{
	@Override
	public void make() {
		System.out.println("자식클래스의 make");
	}
}

public class PolyMain03 {
	public static void main(String[] args) {
		Child2 ch = new Child2();
		ch.make();
		
		System.out.println("=============");
		
		//업캐스팅: 자식> 부모 자동 형변환
		Parent2 p = ch;
		p.make();
	}
}

하지만 메서드 오버라이딩의 경우, 업캐스팅 시 부모 클래스의 참조자료형을 사용해 부모 클래스의 메서드가 잘 호출되던 것과는 얘기가 달라진다.

  1. 앞선 예제와 마찬가지로 Parent2 클래스를 Child2가 상속 받고, 부모클래스인 Parent2의 메서드 make()오버라이딩한다.

  2. 메인 메서드에서 자식클래스인 Child2 객체를 참조변수 ch로 생성한 뒤 오버라이딩한 메서드를 호출 시 다음과 같이 오버라이딩한 것대로 출력된다.
    ex. ch.make(); : 자식클래스의 make

  3. 부모클래스의 타입인 p를 참조자료형으로 하여 형변환 (업캐스팅) 한다.
    ex. Parent2 p = ch;

  4. 그리고 자식클래스인 Child2가 오버라이딩했던 그 메서드를, 부모 참조자료형을 통해 호출 시 다음과 같이 출력된다.
    ex. p.make(); : 자식클래스의 make
    즉, 재정의된 메서드의 경우 업캐스팅 시에도 그 형태를 유지한다.


마지막으로 자료형의 다형성을 활용해 제품을 구매하는 프로그램을 만들어보았다.
> 자료형의 다형성을 활용해 구매 프로그램 만들기

profile
Done is better than perfect.

0개의 댓글