고래씌

[JAVA] 10. 다형성 본문

JAVA/JAVA 기초

[JAVA] 10. 다형성

고래씌 2023. 10. 16. 17:04

1. 다형성

[부모클래스 - Parent]

package com.kh.chap01_poly.part01_basic.model.vo;

public class Parent {
	
	private int x;
	private int y;
	
	public Parent() {
		
	}

	public Parent(int x, int y) {
		super();
		this.x = x;
		this.y = y;
	}

	public int getX() {
		return x;
	}

	public void setX(int x) {
		this.x = x;
	}

	public int getY() {
		return y;
	}

	public void setY(int y) {
		this.y = y;
	}
	
	@Override
	public String toString() {
		return "x : " + x + ", y : " + y;
	}
	
	public void printParent() {
		System.out.println("부모클래스에서 호출됨");
	}
}

[자식클래스 - Child1]

package com.kh.chap01_poly.part01_basic.model.vo;

public class Child1 extends Parent{
	
	private int z;
	
	public Child1() {
		
	}
	
	public Child1(int x, int y, int z) {
		super.setX(x);
		super.setY(y);
		this.z = z;
	}

	public Child1(int z) {
		this.z = z;
	}

	public int getZ() {
		return z;
	}

	public void setZ(int z) {
		this.z = z;
	}
	
	@Override
	public String toString() {
		return super.toString() + ", z : " + z;
	}
	
	public void printChild1() {
		System.out.println("첫번째 자식에서 호출됨");
	}
}

[자식클래스 - Child2]

package com.kh.chap01_poly.part01_basic.model.vo;

public class Child2 extends Parent{

	private int n;
	
	public Child2() {
		
	}
	
	public Child2(int x, int y, int n) {
		super(x, y);
		this.n = n;
	}

	public Child2(int n) {
		super();
		this.n = n;
	}

	public int getN() {
		return n;
	}

	public void setN(int n) {
		this.n = n;
	}
	
	@Override
	public String toString() {
		return super.toString() + ", n : " + n;
	}
	
	public void printChild2() {
		System.out.println("두번째 자식에서 호출됨");
	}

}

1) 부모타입 레퍼런스 변수로 부모타입 객체 다루기

 

하지만!!!!

((child1)p1).printChild1;  => 접근할 수 없다!!! (강제형변환)

Parent p1 = new Parent(); 이기 때문.

Parent p1 = new Child1(); 이면 강제형변환시 접근가능하다.

2) 자식타입 레퍼런스 변수로 자식객체를 다루는 경우

 

Child1 자식클래스의 printChild1 문
Parent 부모클래스의 printParent문

Child1 c1 = new Child();

c1.printParent();  => 자동형변환이 이루어지고 있어서 부모클래스(Parent)의 printParent() 이 호출됨

▶ Child1 레퍼런스 변수로 Parent, Child1에 있는 필드 및 메소드 둘다 접근가능.
▶ Child1 레퍼런스 변수가 Parent에 있는 메소드에 접근시 자동으로 "형변환"이 진행됨.
▶ 자식에서 부모클래스로는 자동형변환(업캐스팅) -> 작은것에서 큰것으로 형변환된것과 같은이치

3) 부모타입, 레퍼런스 변수로 자식 객체를 다루는 경우(다형성 적용)

 

p2.printParent() => 에러 발생하지 않음. Parent클래스 내부 메소드를 참조하기 때문

p2.printChild1(); => 에러 발생. 부모에서 자식으로 자동형변환 X

((Child1)p2).printChild1(); => 부모에서 자식으로 접근하고 싶을대는 Child1 자료형으로 ★강제형변환(다운캐스팅) 후 진행!!

 

★ 정리

클래스 간에도 형변환 가능(단, 상속구조일 경우에만)

1. UpCasting

   - 자식타입 → 부모타입으로 형변환

   - 생략가능(자동형변환 개념)

    ex)

   - 부모 변수 = new 자식객체

 

2. DownCasting

   - 부모타입 → 자식타입으로 형변환

   - 생략불가능(강제형변환 해야함)

     ex)

   - ((자식)부모).자식메소드();

 

2. 다형성을 쓰는 이유

- 부모타입으로부터 파생된 여러가지 타입의 자식객체들을 부모클래스 하나로 다룰 수 있음

 

3. 다형성 장점

 

☞ 다형성이 적용되면 부모타입 레퍼련스 변수 "하나"로 모든 자식객체를 다 받아줄 수 있다!

☞ 하나의 부모타입으로 모든 자식객체들을 다 받을 수 있음 => 코드 수 감소, 생산성 증대, 유지보수 관리.

부모타입은 모든 형변환 가능.

자식클래스에서 자식클래스 강제형변환은 문제 발생!

 

① instanceof 자료형

: 현재 참조하고 있는 레퍼련스 변수(Parent)가 실제로 어떤 객체타입을 참조하고 있는지 확인할 수 있는 연산자

for(int i=0; i<arr.length; i++) {

     if(arr[i] instanceof Child1) {

        ((Child1)arr[i]).printChild1();

      }else {

        ((Child2)arr[i]).printChild2();

      }

}

☞ arr[i]가 실제로 참조하고 있는 객체타입이 Child1이라면 true, 아니라면 false 반환

 

② 동적바인딩 및 정적바인딩

 

 

동적 바인딩 : 프로그램이 실행되기 전에 자동으로 컴파일되면서 정적으로는 현재 레퍼런스 변수(Parent)의 메소드를 가리키게 됨.

→ ctrl 좌클릭으로 확인


단, 참조하고 있는 자식클래스에 해당 메소드가 "오버라이딩"되어 있다면 
프로그램을 시작할때는 동적으로(실제로 실행시 자식클래스의 재정의된 메소드가 실행 동적바인딩
컴파일 단계에서 참조하고 있는 레퍼런스 변수의 메소드를 실행한다고 가리키는 것정적바인딩)