Java - 객체 지향의 특징 (다형성)

제훈·2024년 7월 17일

Java

목록 보기
13/34

상속과 관련돼 있는 다형성에 대해 다뤄보자.

다형성

간단한 트리 구조로
1. A에 있는 자료형을 B가 물려 받고, 그럼 D, E는 A, B의 자료형을 물려받을 수 있다.
2. A에 있는 자료형을 C가 물려 받고, 그럼 F는 A, C의 자료형을 물려받을 수 있다.

활용

Animal

public class Animal {
    public void eat() {
        System.out.println("동물이 먹이를 먹습니다.");
    }

    public void run() {
        System.out.println("동물이 달립니다.");
    }

    public void cry() {
        System.out.println("동물이 울음소리를 냅니다.");
    }

}

Rabbit

public class Rabbit extends Animal {
    @Override
    public void eat() {
        System.out.println("토끼가 풀을 뜯어먹고 있습니다.");
    }

    @Override
    public void run() {
        System.out.println("토끼가 달립니다 껑충");
    }

    @Override
    public void cry() {
        System.out.println("토끼가 울음소리를 냅니다. 끼익~~");
    }

    public void jump() {
        System.out.println("토끼가 점프를 뜁니다!");
    }
}

Tiger

public class Tiger extends Animal {
    @Override
    public void eat() {
        System.out.println("호랑이가 고기를 뜯어먹습니다.");
    }

    @Override
    public void run() {
        System.out.println("호랑이는 웬만에선 달리지 않습니다.");
    }

    @Override
    public void cry() {
        System.out.println("호랑이가 울부짖습니다.");
    }

    public void bite() {
        System.out.println("호랑이가 물어뜯습니다.");
    }
}

Tiger, Rabbit은 Animal을 상속해서 Animal의 자료형을 물려받을 수 있지만, Animal은 Tiger, Rabbit의 존재를 모른다.

Application

package com.ohgiraffers.section01.polymorphism;

public class Application {
    public static void main(String[] args) {
        /* 수업목표. 다형성과 타입 형변환에 대해 이해할 수 있다. */
        Animal animal = new Animal();
        animal.eat();
        animal.run();
        animal.cry();

        System.out.println();

        Tiger tiger = new Tiger();
        tiger.eat();
        tiger.run();
        tiger.cry();
        tiger.bite();

        System.out.println();

        Rabbit rabbit = new Rabbit();
        rabbit.eat();
        rabbit.run();
        rabbit.cry();
        rabbit.jump();

        Animal an1 = new Animal();  // 다형성 X
        Animal an2 = new Tiger();   // 다형성 O
        Animal an3 = new Rabbit();  // 다형성 O
    }
}

위 코드의 맨 밑 2줄을 보면 다형성 적용을 한 것을 알 수 있다.

  • 부모 타입으로 자식 인스턴스의 주소값 저장

아래 2가지는 다형성을 적용한 것이 아니다. 애초에 에러가 뜬다.

Tiger tiger = new Animal(); // 다형성 X
Rabbit rabbit = new Animal(); // 다형성 X

AnimalTigerRabbit이 아니기 때문에 안 된다. (반대는 가능하니까 O)


동적 바인딩

Application 위 코드 아래에 추가해보자.

        System.out.println("===== 동적 바인딩 확인하기 =====");
        an1.cry();
        an2.cry();
        an3.cry();

cry()를 들어가보면 셋다 Animalcry 메소드를 쳐다보고 있다.

컴파일 시점 -> 정적 바인딩을 통해 Animal 타입의 cry() 메소드로 생각한다.
실행하면 (런타임 시점) 객체가 생성된다. 그래서 new Tiger(), new Rabbit() 들로 인해 어떤 타입들이 구체화 돼 있는지 알 수 있어서 사진과 같이 출력되는 것이다.

동적바인딩의 조건
1. 상속
2. 오버라이딩

동적 바인딩 : 컴파일 당시에는 해당 타입의 메소드와 연결돼 있다가
런타임 당시 실제 객체가 가진 오버라이딩 된 메소드로 바인딩이 바뀌어 동작하는 것을 의미한다.


컴파일 시점, 런타임 시점 시 주의사항

부모타입을 자식타입으로 강제 형변환 하는 것은 가능하다 (조심해야 함)

Application

         ((Tiger) an3).cry(); 
         // 컴파일 시점에서 에러 발생 X지만, 런타임 시점에 에러 발생

컴퓨터는 an3 를 Animal an3 = new Rabbit() 으로 적어놔도 컴파일 시점에서 an3는 현재 Animal 자료형인 것이다.

그래서 위 코드에서는 an3는 Animal 이기에 강제 형변환이 가능하지만, 런타임 시 an3는 Rabbit 타입인걸 알게되므로 런타임 에러가 생기는 것이다.


instanceof 연산자

		if (an3 instanceof Tiger) {
            ((Tiger) an3).cry();
        }

        if (an3 instanceof Animal) {
            System.out.println("Animal은 맞지");
        }

an3는 위에서 Rabbit으로 만들었었는데 둘다 가능할까?

아래 조건문의 실행부분만 가능하다.

instanceof : 해당 객체의 타입을 런타임 시점에 확인하기 위한 연산자


업캐스팅, 다운캐스팅

Animal an4 = new Tiger();       // 다형성을 적용, 자동형변환(auto up-casting), 묵시적 형변환
Rabbit rabbit2 = (Rabbit)an3;   // 다형성 적용 X, 강제형변환(down-casting), 명시적 형변환

Tiger가 상위 타입 형변환으로 Animal로 클래스 형변환이 되는 것과
an3는 Animal인데 Rabbit으로 down-casting 된다.

profile
백엔드 개발자 꿈나무

0개의 댓글