최원종의 개발 블로그

다형성(Polymorphism) 본문

Java/Java 객체지향

다형성(Polymorphism)

chl6698 2026. 3. 5. 10:39

다형성 개념.

다형성은 하나의 데이터 타입이 다양한 형태로 바라볼 수 있는 것.

 

다형성은 객체 지향 프로그래밍에서 중요한 개념 중 하나이다.

이는 한 요소(ex: 메서드, 클래스)가 여러 형태를 가질 수 있는 능력을 의미한다.

다형성은 코드의 유연성과 재사용성을 높여주며, 상속, 추상클래스, 인터페이스와 함께 사용됨.


다형성 코드

package com.tenco.polymorphism;

import com.tenco.Inheritance.A;

public class Animal {

    public void move() {
        System.out.println("동물이 움직입니다");
    }

    public void eating() {
        System.out.println("먹이를 먹습니다");
    }

}//end of animal class

class Human extends Animal {

    @Override //주석 + 힌트 자식클래스에서 부모클래스 재정의 하는 것을 오버라이드라고 함
    public void move() {
        System.out.println("사람이 두 발로 걷습니다.");
    }

    @Override
    public void eating() {
        System.out.println("밥을 먹습니다");
    }

    public void readBooks() {
        System.out.println("책을 읽습니다");
    }
}//end of Human class

class Tiger extends Animal {
    @Override
    public void move() {
        System.out.println("호랑이가 살금살금 네 발로 걸어요");
    }

    @Override
    public void eating() {
        System.out.println("호랑이가 사냥을 합니다");
    }
}

 

-AnimalMain

package com.tenco.polymorphism;

/**
 * 하나의 데이터 타입을 다양한 형태로 바라 보는 것(다형성)
 * 상속 관계
 */
public class AnimalMain {

    public static void main(String[] args) {

        Animal animal = new Animal();
        animal.move();
        animal.eating();
        System.out.println("-----------------");

        // 다형성 - Animal 과 Tiger는 상속관계 이기 때문기 때문에 다형성이 적용이 되고
        // Tiger 타입은 Animal 타입으로 바라 볼 수 있다.
        Animal animalTiger = new Tiger();
        animalTiger.move();
        animalTiger.eating();
        // 부모 클래스 타입으로 자식 객체를 생성 했을 때..
        // [[컴파일 시점]]에는 부모 타입에 메서드가 있는지 없는지 여부만 확인한다.
        // 하지만 실행 시점에는 생성성 객체의 메서드가 먼저 있는지 확인하다.

        System.out.println("---------------------");
        Animal animalHuman = new Human();
        animalHuman.move();
        animalHuman.eating();
        // animalHuman.readBooks();
        // 왜 readBooks() 오류가 날까?
        // 컴파일 시점에는 Animal 타입만 확인하기 때문에
        // 부모 클래스인 Animal 클래스 안에는 readBooks() 메소드가 없기 때문이다
        System.out.println("------------------------------");

        Human human = new Human();
        human.move();
        human.eating();
        human.readBooks();

    } // end of main

}

업캐스팅과 다운 캐스팅

업캐스팅과 다운캐스팅은 객체 지향 프로그래밍에서 다형성을 활용할 때 사용되는 개념.

 

업캐스팅(Upcasting)

  • 업캐스팅은 부모 클래스의 참조변수로 자식 클래스의 객체를 참조하는 것
  • 부모 클래스의 데이터 타입으로 자식 클래스의 객체를 대입하는 것을 의미.
  • 업캐스팅은 자동으로 이루어진다
Animal animal = new Dog(); // 업캐스팅

 

다운캐스팅(Downcasting)

  • 다운캐스팅은 부모 클래스의 참조 변수를 자식 클래스의 객체로 변환하는 것을 의미
  • 다운캐스팅은 명시적으로 형변환을 해야 한다.
  • 다운캐스팅은 업캐스팅된 객체가 실제로 자식 클래스의 객체일 때만 가능하다. 
  • 그렇지 않으면 ClassCastException(예외)이 발생할 수 있다.
Animal animal = new Dog(); // 업캐스팅
Dog dog = (Dog) animal; // 다운캐스팅

 

코드

package com.tenco.polymorphism;

/**
 * 하나의 데이터 타입을 다양한 형태로 바라 보는 것(다형성)
 * 상속 관계
 */
public class AnimalMain {

    public static void main(String[] args) {
    
      
        Animal animalTiger = new Tiger();  // 업캐스팅된 상태
        // ** 다운 캐스트 해보기 **
        Tiger tiger = (Tiger) animalTiger;
        System.out.println("---------------------");
       
        Animal animalHuman = new Human();
        animalHuman.move();
        animalHuman.eating();

        // 다운 캐스팅 해보기
        Human humanDownCasting = (Human) animalHuman;
        humanDownCasting.readBooks();
        ((Human)animalHuman).readBooks(); // 축약해서 호출 가능

        System.out.println("------------------------------");
        // 강제 형 변환 
        int a = (int)1.1;
        
    } // end of main

}

-FruitMain

package com.tenco.polymorphism;

import com.tenco.Inheritance.B;

public class FruitMain {
    public static void main(String[] args) {

        Fruit fruit1 = new Banana();//업캐스팅된 상태 -> 부모타입으로 자식 객체를 생성
        Fruit fruit2 = new Peach();

        fruit1.showInfo();
        fruit2.showInfo();

        System.out.println("----------------");
        //바나나 원산지만 콘솔 창에 출력하시오
        String origin = ((Banana) fruit1).origin;
        System.out.println("바나나 원산지 : " + origin);

        System.out.println("-----------------");
        //키워드 - 업캐스팅된 상태에서 사용할 수 있는 instanceof 연산자를 사용해 보자.
        //현재 생성된 객체의 타입을 확인할 대 사용하는 연산자
        if (fruit1 instanceof Banana) {
            System.out.println("fruit1 타입의 샐제 자식 타입은 바나나 타입입니다.");
        }

        if (fruit2 instanceof Banana) {
            System.out.println("fruit2 타입의 실제 자식 타입은 바나나 타입입니다");
            String resultOrigin = ((Banana) fruit2).origin;
        } else if (fruit2 instanceof Peach) {
            System.out.println("fruit2 타입의 실제 자식 타입은 복숭아 타입입니다");
        } else {
            System.out.println("그냥 과일 타입입니다");
        }
    }
}

 

-다형성 활용

package com.tenco.polymorphism;

public class Banana extends Fruit {
//    String name;
//    int price;
    String origin; //바나나 클래스만 가지고 있음

    public Banana() {
        this.name = "델몬트 바나나";
        this.price = 5_000;
        this.origin = "필리핀";
    }

    public void sale() {
        System.out.println("--바나나 할인 기간--");
        System.out.println("할인된 가격 : " + (this.price - 1000));
    }
}

 

-EMart

package com.tenco.polymorphism;

import com.tenco.Inheritance.B;

public class EMart {
    public static void main(String[] args) {


        Banana[] bananas = new Banana[10];
        Peach[] peaches = new Peach[10];

        //---------------------------------------
        //다형성에 장점 활용
        Fruit[] fruits = new Fruit[4];
        fruits[0] = new Banana();
        fruits[1] = new Peach();
        fruits[2] = new Banana();
        fruits[3] = new Peach();

        for (int i = 0; i < fruits.length; i++) {
            fruits[i].showInfo();

            // 바나나 타입인지 검사
            if (fruits[i] instanceof Banana) {
                ((Banana) fruits[i]).sale();
            }
        }
    }
}

 

다형성 특징

  • 하나의 코드가 여러 자료형으로 구현되어 실행되는 것
  • 같은 코드에서 여러 다른 실행 결과가 나온다
  • 정보은닉, 상속과 더불어 객체지향 프로그래밍의 가장 큰 특징 중 하나
  • 다형성을 잘 활용하면 유연하고 확장성 있고, 유지보수가 편리한 프로그램을 만들 수 있다
  •  

- (.) 연산자 여러 번 사용해 보기

1. 포함관계

package com.tenco.polymorphism;

class A {
  B b = new B();
}

class B {
   C c = new C();
}

class C {
   D d = new D();
}

class D {
    void showInfo() {
        System.out.println("D 클래스의 showInfo 메서드 호출");
    }
}


public class Main {

    public static void main(String[] args) {
        // . 점 연산자의 여행
        // A , B , C , D 설계

        // 1. 가장 바깥쪽에 있는 객체 생성
        A a = new A();
        // 2. 깊숙이 들어있는 D 의 메서드 호출
        // a(의) -> b(의) -> c(의) -> d(의) -> shoInfo()
        // 최종 결과 코딩
        // a.b.c.d.shoInfo();
        // "D 클래스 showInfo() 를 호출 했습니다."
        a.b.c.d.showInfo();
        a = null;

    }
}

 

2. 연관관계

package com.tenco.polymorphism;

class A {
    //    B b = new B();//포함관계
    B b;

    //외부에서 주입 받는 방법 2가지
    //1. 생성자 주입<- 많이 쓰는 방법
    //2. 메서드 통해서 주입
    public A(B b) {
        this.b = b;
    }
}

class B {
    //    C c = new C();
    C c;

    public B(C c) {
        this.c = c;
    }
}

class C {
    //    D d = new D();
    D d;

    public C(D d) {
        this.d = d;
    }
}

class D {

    public void showInfo() {
        System.out.println("D클래스 showInfo()를 호출했습니다");
    }
}

public class Main {
    public static void main(String[] args) {
        //.점 연산자의 여행
        //A,B,C,D설계

        //1.가장 바깥쪽에 있는 객체 생성
        D d = new D();
        C c = new C(d);
        B b = new B(c);
        A a = new A(b);

        //2. 깊숙이 들어있는 D의 메서드 호출
        //a(의) -> b(의) ->(c)의 -> d(의) -> showInfo()
        //최종 결과 코딩
        a.b.c.d.showInfo();

        //"D클래스 showInfo()를 호출했습니다

        //연관 관계로 코드를 수정해 주세요
        //포함 --> 연관 --> 외부에서 주입 받도록 해야하고 독립적으로 객체들이 힙에
        //존재할 수 있게 설계
    }
}

 

'Java > Java 객체지향' 카테고리의 다른 글

인터페이스(interface)  (0) 2026.03.06
추상 클래스(abstract class)  (0) 2026.03.06
포함관계와 집합관계  (0) 2026.03.04
연관관계(Association)  (0) 2026.03.04
상속과 접근제어 지시자  (0) 2026.03.04