1️⃣2️⃣ 다형성 – 하나의 객체, 여러 형태로 변하다! 🌈✨

🎬 상상해봐

너는 공격을 할 수 있는 여러 캐릭터를 만들었어.
이 캐릭터들은 각기 다른 공격 방식을 가질 거야.
그렇다면, 하나의 메서드로 모든 캐릭터의 공격을 처리할 수 있을까?
바로 다형성 덕분에 하나의 메서드다양한 캐릭터들의 공격 방식을 처리할 수 있어!


🧙‍♂️ 1. 다형성이란?

다형성같은 이름의 메서드다양한 형태로 동작하는 능력이야.
즉, 상속인터페이스를 통해 하나의 메서드여러 클래스에서 다르게 동작하게 할 수 있어.

public class Hero {

    String name;
    public Hero(String name) {
    	this.name = name;
    }
    
    public void attack() {
    	System.out.println(name + "이(가) 검으로 공격했다!");
    }
}

public class Dragon {

    String name;
    public Dragon(String name) {
    	this.name = name;
    }
    
    public void attack() {
    	System.out.println(name + "이(가) 불을 뿜었다!");
    }
}

🦸‍♂️ 2. 다형성 사용하기

이제 HeroDragon 클래스가 같은 attack() 메서드를 가지고 있어.
그렇다면 다형성을 이용해서 동일한 메서드다양한 객체를 처리할 수 있어!

public class Main {

    public static void main(String[] args) {
        Hero hero1 = new Hero("철수");
        Dragon dragon1 = new Dragon("불사조");

        hero1.attack(); // 철수가 검으로 공격했다!
        dragon1.attack(); // 불사조가 불을 뿜었다!
    }
}

다형성 덕분에 공격하기라는 동일한 메서드 이름을 사용하면서도,
각각의 클래스가 다르게 동작하게 만들어 줬어.


🧩 3. 다형성의 장점

  • 유연한 코드: 하나의 메서드를 여러 객체에서 사용할 수 있어.
  • 코드의 재사용성: 같은 메서드를 사용해도, 다양한 객체에 맞게 동작하도록 만들 수 있어.
  • 확장성: 새로운 클래스가 추가되어도, 기존 코드는 수정할 필요가 없어!

🔄 4. 다형성과 참조 변수

다형성을 사용할 때 중요한 점은 참조 변수야.
다형성은 상위 클래스인터페이스 타입의 참조 변수를 사용하여,
하위 클래스구현 클래스다르게 참조할 수 있다는 점이야!

public class Main {

    public static void main(String[] args) {
        Hero hero1 = new Hero("철수");
        Dragon dragon1 = new Dragon("불사조");

        // 다형성 활용: Hero 타입의 참조 변수로 Hero 객체를 참조
        Attackable attackableHero = hero1;
        attackableHero.attack(); // 철수가 검으로 공격했다!

        // 다형성 활용: Dragon 타입의 참조 변수로 Dragon 객체를 참조
        Attackable attackableDragon = dragon1;
        attackableDragon.attack(); // 불사조가 불을 뿜었다!
    }
}

Attackable 인터페이스 타입의 참조 변수로, HeroDragon 객체를 각각 다르게 참조하면서도
공격하기라는 같은 메서드를 호출할 수 있어!


🔧 5. 메서드 오버라이딩과 다형성

다형성은 메서드 오버라이딩과 함께 사용할 때 더욱 강력해져!
상속받은 클래스에서 메서드를 재정의(오버라이딩)하여, 다양한 형태로 동작하게 만들 수 있어.

public class Hero {

    String name;
    public Hero(String name) {
    	this.name = name;
    }

    public void attack() {
    	System.out.println(name + "이(가) 검으로 공격했다!");
    }
}

public class FlyingHero extends Hero {

    public FlyingHero(String name) {
    	super(name);
    }

    @Override public void attack() {
    	System.out.println(name + "이(가) 하늘에서 공격했다!");
    }
}
public class Main {

    public static void main(String[] args) {
        Hero hero1 = new Hero("철수");
        Hero hero2 = new FlyingHero("영희");

        hero1.attack(); // 철수가 검으로 공격했다!
        hero2.attack(); // 영희가 하늘에서 공격했다!
    }
}

FlyingHero 클래스는 Hero 클래스를 상속받아서 attack() 메서드를 오버라이딩했어.
이제 다형성 덕분에 두 객체가 동일한 참조 변수로 처리되지만,
각기 다르게 동작하게 되지!


🧠 정리 타임

개념의미예시
다형성 같은 메서드가 다양한 클래스에서 다르게 동작하는 능력 hero1.attack() / dragon1.attack()
참조 변수 상위 클래스나 인터페이스 타입의 참조 변수로 여러 객체를 참조 Attackable attackableHero = hero1;
메서드 오버라이딩 상속받은 클래스에서 메서드를 재정의하여 다르게 동작시킴 public void attack() { ... }

🎮 실전 미션 – 공격 방식이 다른 히어로들 만들기

public class Hero {

    String name;
    public Hero(String name) {
    	this.name = name;
    }

    public void attack() {
    	System.out.println(name + "이(가) 검으로 공격했다!");
    }
}

public class FireHero extends Hero {

    public FireHero(String name) {
    	super(name);
    }
    
    @Override
    public void attack() {
    	System.out.println(name + "이(가) 불꽃을 뿜었다!");
    }
}
public class Main {

    public static void main(String[] args) {
    Hero hero1 = new Hero("철수");
    Hero hero2 = new FireHero("영희");
    
    hero1.attack(); // 철수가 검으로 공격했다!
    hero2.attack(); // 영희가 불꽃을 뿜었다!
    }
}

✨ 마무리 요약

다형성을 사용하면, 하나의 메서드다양한 클래스에서 다르게 동작할 수 있어.
이제 유연하고 확장성 있는 코드를 만들 수 있게 되었어!


다음 13단원에서는 예외 처리에 대해 배울 거야.
예외 처리는 프로그램이 오류를 만났을 때 예외적인 상황을 처리해주는 중요한 기술이야.
이걸 배우면, 안전하고 안정적인 프로그램을 만들 수 있어!