0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

포켓몬 육성과 같이 오브젝트 지향을 가족으로 배울 수 있는 Java 초클래스 입문 ~"좋아"가 배움으로 바뀌는 마법의 도감~

Last updated at Posted at 2025-05-13

📚 목차


🧩 제1장 포켓몬 도감 만들기! 클래스 설계도

🎯 1.1 오브젝트란?

🌟 포켓몬도 오브젝트? 실생활에서 느끼는 객체지향의 세계

포켓몬 세계에서 피카츄나 파이리 같은 모든 포켓몬은 '오브젝트'입니다.
현실 세계로 예를 들면, '자전거'나 '스마트폰'도 오브젝트입니다.

오브젝트에는 두 가지 요소가 있습니다:

  • 🧬 속성 (필드): 예를 들어 피카츄의 '타입', '레벨' 등
  • 🛠 행동 (메서드): 피카츄가 사용하는 '10만 볼트'나 '울음소리' 같은 기술

🏗 1.2 클래스를 만들자

📘 도감에 싣기 전에! 클래스라는 설계도의 중요성

클래스란 '오브젝트의 설계도'입니다.
예를 들어 '포켓몬'이라는 클래스를 만들면, 이를 바탕으로 피카츄, 파이리 등 다양한 포켓몬 오브젝트를 만들 수 있습니다.


🛠 클래스 정의 예시 (Java)

public class Pokemon {
    String name; // 포켓몬 이름
    String type; // 타입 (예: 전기)
    int level;   // 레벨

    public void introduce() {
        System.out.println("안녕! 나는 " + name + ", 타입은 " + type + ", 레벨은 " + level + "이야!");
    }
}

🧪 1.3 정리와 테스트

✅ 클래스의 핵심 정리

요소 설명
클래스 설계도 (포켓몬의 공통 정보)
오브젝트 실제로 생성된 피카츄나 파이리 등
속성 이름, 타입, 레벨
메서드 자기소개 등의 행동

📝 연습문제

  1. 자신만의 포켓몬을 생각해서 Pokemon 클래스로 표현해 보세요.
  2. introduce() 메서드에 '사용 가능한 기술'도 소개할 수 있도록 확장해 보세요.

🎯 제2장 몬스터볼에서 GET! 인스턴스 생성과 사용법

🧱 2.1 인스턴스를 만들자

🥚 포켓몬을 소환하라! new 연산자와 생성자의 마법

Java에서는 new 키워드를 사용하여 클래스에서 오브젝트(인스턴스)를 생성합니다.
이것은 마치 몬스터볼에서 포켓몬을 꺼내는 것과 같습니다.

Pokemon pika = new Pokemon();
  • Pokemon: 설계도(클래스)의 이름
  • pika: 생성된 피카츄 인스턴스
  • new Pokemon(): 새로운 포켓몬을 만드는 마법의 주문

🔓 2.2 게터와 세터의 사용법

🔍 "너의 HP는 몇이야?" 게터로 상태 확인

public String getName() {
    return name;
}

💪 "레벨 업!" 세터로 포켓몬을 강화하자

public void setLevel(int lvl) {
    level = lvl;
}

게터와 세터를 사용하는 이유는?
-> 캡슐화(encapsulation) 를 활용하기 위해서입니다.


🧬 캡슐화란?

클래스 내부 데이터를 외부에서 직접 변경하지 못하게 막고, 안전하게 다루는 방법

❌ 잘못된 예 (캡슐화 안됨)

public class Pokemon {
    public int hp;
}
...
pikachu.hp = -100; // 위험한 직접 접근!

✅ 올바른 예 (게터와 세터 사용)

public class Pokemon {
    private int hp;

    public void setHp(int hp) {
        if (hp >= 0) {
            this.hp = hp;
        } else {
            System.out.println("HP는 0 이상이어야 합니다.");
        }
    }

    public int getHp() {
        return this.hp;
    }
}

🛠 2.3 메서드를 추가하자

⚡ "10만 볼트!" 기술을 사용하는 메서드

public void useMove() {
    System.out.println(name + "의 " + move + "! 효과는 굉장했다!");
}

✅ 고급편: @Override 와 toString

@Override
public String toString() {
    return "포켓몬: " + name + " / 타입: " + type + " / 레벨: " + level + " / 기술: " + move;
}

@Override는 필수는 아니지만, 매우 권장됩니다.


🎯 2.4 정리와 테스트

용어 설명
인스턴스 new 연산자로 만든 객체
게터 값을 읽는 메서드
세터 값을 설정하는 메서드
@Override 부모 클래스 메서드를 재정의할 때 사용
toString 객체 정보를 문자열로 출력

💻 최종 예시 코드

public class Pokemon {
    private String name;
    private String type;
    private int level;
    private String move;

    public void setName(String name) { this.name = name; }
    public void setType(String type) { this.type = type; }
    public void setLevel(int level) { this.level = level; }
    public void setMove(String move) { this.move = move; }

    public String getName() { return name; }
    public String getType() { return type; }
    public int getLevel() { return level; }
    public String getMove() { return move; }

    public void useMove() {
        System.out.println(name + "의 " + move + "! 효과는 굉장했다!");
    }

    @Override
    public String toString() {
        return "포켓몬: " + name + " / 타입: " + type + " / 레벨: " + level + " / 기술: " + move;
    }
}

public class Main {
    public static void main(String[] args) {
        Pokemon pika = new Pokemon();
        pika.setName("피카츄");
        pika.setType("전기");
        pika.setLevel(25);
        pika.setMove("10만 볼트");

        System.out.println(pika);
        pika.useMove();
    }
}

🧩 이 예시로 클래스 → 인스턴스 생성 → 값 설정 → 메서드 실행의 흐름을 체험할 수 있습니다!


🛡 제3장 포켓몬의 비밀을 지켜라! 클래스의 구조

🔐 3.1 다른 클래스에서의 접근 제한

🧳 "그 HP는 보여줄 수 없어!" private와 public의 경계선

public class Pokemon {
    private int hp;

    public int getHp() {
        return hp;
    }

    public void setHp(int hp) {
        this.hp = hp;
    }
}

📝 private은 비공개, public은 공개를 의미합니다.


🧩 회색 지대 속성! 아무 것도 안 썼을 때의 세계

접근 제한자를 생략하면 동일한 패키지 내에서는 접근 가능합니다. 이를 default 접근이라고 부릅니다.


🛡 비밀스러운 스테이터스를 보호하라! 캡슐화의 진수

**캡슐화(encapsulation)**는 데이터를 클래스 안에 감추고 외부에서 직접 접근을 막는 개념입니다.
포켓몬 게임에서 상태창을 트레이너만 조작할 수 있는 것처럼요!


⚙️ 3.2 멤버의 구조

⚡ "모든 포켓몬의 공통 특성" static 멤버의 힘

public class Pokemon {
    public static final int MAX_LEVEL = 100;
}

📝 static은 클래스 전체에서 공유되는 변수 또는 메서드를 의미합니다.


🧬 "이 피카츄만의 특성" 인스턴스 멤버의 개성

public class Pokemon {
    private int level; // 인스턴스마다 개별 보유
}

⚠️ static과 instance, 공존 가능할까?

가능합니다. 차이를 명확히 이해하는 것이 중요합니다.

public class Pokemon {
    public static final int MAX_LEVEL = 100;
    private int level;

    public boolean isMaxLevel() {
        return level == MAX_LEVEL;
    }
}

🧱 3.3 생성자의 구조

🌀 같은 이름, 다른 방식? 오버로딩의 마법

public Pokemon() {
    this.name = "피카츄";
}

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

🌈 "컬러풀 포켓몬" 다양한 생성자 만들기

public Pokemon(String name, int level, String type) {
    this.name = name;
    this.level = level;
    this.type = type;
}

🔁 this()로 생성자 연결하기

public Pokemon(String name, int level) {
    this(name, level, "노말");
}

🧊 아무 것도 지정하지 않아도 생기는 포켓몬?

생성자를 정의하지 않으면 Java가 자동으로 기본 생성자를 생성해줍니다.
하지만 다른 생성자가 정의되어 있으면 기본 생성자는 자동 생성되지 않으므로 주의!


🧪 3.4 정리와 테스트

📘 3장 요약: 캡슐화와 멤버 관리 핵심

항목 내용
접근 제한자 데이터 노출 여부 설정
private 외부에서 볼 수 없음
public 어디서나 사용 가능
static 모든 포켓몬 공통 특성
생성자 포켓몬 생성 시 초기 설정 메서드
this 자기 자신을 가리킴, 생성자 호출 가능

🎮 테스트 코드

public class Pokemon {
    private String name;
    private String type;
    private int level;
    public static final int MAX_LEVEL = 100;

    public Pokemon() {
        this("피카츄", 5, "전기");
    }

    public Pokemon(String name, int level, String type) {
        this.name = name;
        this.level = level;
        this.type = type;
    }

    public String getName() { return name; }
    public String getType() { return type; }
    public int getLevel() { return level; }

    public void setLevel(int level) { this.level = level; }

    public boolean isMaxLevel() {
        return level == MAX_LEVEL;
    }

    public void introduce() {
        System.out.println("나는 " + name + "! 타입: " + type + ", 레벨: " + level);
    }
}

public class Main {
    public static void main(String[] args) {
        Pokemon pika = new Pokemon();
        pika.introduce();

        Pokemon eve = new Pokemon("이브이", 10, "노말");
        eve.introduce();

        System.out.println("이브이는 최대 레벨인가? " + eve.isMaxLevel());
    }
}

🧩 이 예시로 캡슐화, static 변수, 생성자 오버로딩을 체험할 수 있습니다!


🧭 제4장 포켓몬을 가리켜라! 인스턴스와 참조의 비밀

🎯 4.1 참조란?

🎈 몬스터볼과 포켓몬의 관계? 참조의 신비한 역할

Java에서 참조(reference)란 오브젝트의 **위치(주소)**를 저장하는 변수입니다.
몬스터볼은 포켓몬을 담는 그릇이죠. Java에서는 이 몬스터볼이 참조입니다.

Pokemon pika1 = new Pokemon(); // 포켓몬 생성
Pokemon pika2 = pika1;         // pika1과 같은 포켓몬을 가리킴

📝 pika2pika1같은 포켓몬 인스턴스를 참조할 뿐, 새로 생성된 것이 아닙니다.


👀 4.2 참조를 의식하자

🧪 "복사했는데 같은 포켓몬?" 변수 간 대입의 진실

pika2.setLevel(50);
System.out.println(pika1.getLevel()); // 50이 출력됨

📌 오브젝트는 복사되는 것이 아니라 참조 주소만 전달되는 것이 기본입니다.


🧊 4.3 완전히 불변의 클래스를 만들자

🧼 "전설의 포켓몬, 아무도 바꿀 수 없다!" 완전 불변 구현

public final class Pokemon {
    private final String name;
    private final String type;
    private final int level;

    public Pokemon(String name, String type, int level) {
        this.name = name;
        this.type = type;
        this.level = level;
    }

    public String getName() { return name; }
    public String getType() { return type; }
    public int getLevel() { return level; }
}

🛡 모든 필드에 final을 붙이면 값이 한 번 정해지면 변경 불가한 클래스가 됩니다.


🧬 4.4 참조형

🧪 "기본형과의 차이는?" Java의 타입 시스템

타입 종류 예시 특징
기본형 (primitive) int, double 값 자체를 저장
참조형 (reference) String, Pokemon 객체의 주소를 저장

⚠️ "비어있는 몬스터볼?" null의 정체

Pokemon pika = null;
pika.introduce(); // NullPointerException!

🚨 null은 아직 객체가 생성되지 않은 상태를 의미하며, 사용 시 에러 발생!


🧪 4.5 정리와 테스트

🧾 4장 요약: 참조와 불변 이해

키워드 설명
참조 객체의 위치를 가리킴
같은 참조 변수 대입 시 같은 객체를 가리킴
null 아무 것도 없는 상태
불변 (immutable) 값이 절대 변경되지 않는 설계

💻 종합 테스트 코드

public final class Pokemon {
    private final String name;
    private final String type;
    private final int level;

    public Pokemon(String name, String type, int level) {
        this.name = name;
        this.type = type;
        this.level = level;
    }

    public String getName() { return name; }
    public String getType() { return type; }
    public int getLevel() { return level; }

    public void introduce() {
        System.out.println("나는 " + name + "! 타입: " + type + ", 레벨: " + level);
    }
}

public class Main {
    public static void main(String[] args) {
        Pokemon pika1 = new Pokemon("피카츄", "전기", 25);
        Pokemon pika2 = pika1; // 동일 참조

        pika1.introduce();
        pika2.introduce();

        // 아래 코드는 NullPointerException을 발생시킴
        // Pokemon empty = null;
        // empty.introduce();
    }
}

🔍 이 예시로 참조 개념과 null 위험성을 직접 체험할 수 있습니다!


🧪 제5장 오리지널 포켓몬을 설계하라! 오브젝트 모델링

🧱 5.1 기능을 구현하는 클래스

📝 어떤 포켓몬을 만들까? 전체적인 구조를 생각해보자

포켓몬 게임에서는 이름, 타입, 레벨, 기술 등 다양한 정보가 필요합니다.
이 정보를 클래스로 어떻게 표현할지를 생각하는 것이 바로 오브젝트 모델링입니다.


🧮 "특성과 기술을 정하자" 클래스 정의 예시

public class Pokemon {
    private String name;
    private String type;
    private int level;
    private String[] moves;

    public Pokemon(String name, String type, int level, String[] moves) {
        this.name = name;
        this.type = type;
        this.level = level;
        this.moves = moves;
    }

    public void introduce() {
        System.out.println("이름: " + name + " / 타입: " + type + " / 레벨: " + level);
        System.out.println("기술 목록:");
        for (String move : moves) {
            System.out.println("- " + move);
        }
    }
}

🚀 "정말 이대로 괜찮을까?" 설계 검토 포인트

  • 기술은 몇 개까지 허용할까? → 배열로 유연하게 대응
  • 레벨 상한은? → static final 사용
  • 여러 타입 지원? → 이번엔 단일 타입만 사용

⚙️ 구현 시작! 클래스 → 코드 변환

String[] fushiMoves = {"몸통 박치기", "덩굴채찍", "독가루"};
Pokemon fushi = new Pokemon("이상해씨", "풀", 10, fushiMoves);
fushi.introduce();

📦 5.2 record

🆕 Java 16 신기능! record는 누구인가?

Java 16부터는 record로 간단한 데이터 클래스를 정의할 수 있습니다.

public record SimplePokemon(String name, String type, int level) {}

✨ "간편 도감 등록" record의 장점

  • 생성자
  • getter
  • toString()
  • equals()

이 모든 기능이 자동으로 생성됩니다.

SimplePokemon zenigame = new SimplePokemon("꼬부기", "물", 8);
System.out.println(zenigame.name());
System.out.println(zenigame);

🧠 기능 확장도 가능

public record SimplePokemon(String name, String type, int level) {
    public boolean isStarter() {
        return level <= 10;
    }
}

🔒 전설 포켓몬은 변하지 않는다! 불변 record

record의 필드는 모두 final이므로 수정 불가능.
뮤츠나 루기아 같은 전설의 포켓몬에 적합한 구조입니다.


🪄 3줄로 포켓몬 만들기!

SimplePokemon hitokage = new SimplePokemon("파이리", "불꽃", 5);
System.out.println("팀 후보: " + hitokage.name());

🎯 5.3 정리와 테스트

✅ 모델링과 record 요약

개념 설명
모델링 현실의 개체를 프로그램 구조로 설계
필드 이름, 타입, 기술 등 정보
메서드 소개, 기술 사용 등 동작
record 간단한 불변 데이터 클래스
불변 값이 절대 바뀌지 않는 구조

💻 종합 예제 코드

public class Pokemon {
    private String name;
    private String type;
    private int level;
    private String[] moves;

    public Pokemon(String name, String type, int level, String[] moves) {
        this.name = name;
        this.type = type;
        this.level = level;
        this.moves = moves;
    }

    public void introduce() {
        System.out.println("이름: " + name + " / 타입: " + type + " / 레벨: " + level);
        System.out.println("기술:");
        for (String move : moves) {
            System.out.println("- " + move);
        }
    }
}

public record SimplePokemon(String name, String type, int level) {
    public boolean isStarter() {
        return level <= 10;
    }
}

public class Main {
    public static void main(String[] args) {
        String[] moves = {"몸통 박치기", "덩굴채찍", "독가루"};
        Pokemon bulbasaur = new Pokemon("이상해씨", "풀", 10, moves);
        bulbasaur.introduce();

        SimplePokemon charmander = new SimplePokemon("파이리", "불꽃", 5);
        System.out.println("팀 후보: " + charmander.name());
        System.out.println("스타터? " + charmander.isStarter());
    }
}

🧩 이 예시로 클래스와 record를 활용한 데이터 정의를 모두 경험할 수 있습니다!


🧬 제6장 진화의 비밀을 밝혀라! 상속이라는 혈통

📊 6.1 클래스 다이어그램

📚 "포켓몬 도감의 뒷면" 클래스 다이어그램 해독법

Java의 상속은 도감의 진화 트리와 유사합니다.
예) 피츄 → 피카츄 → 라이츄

Pokemon (부모 클래스)
  └── Pikachu (자식 클래스)
       └── Raichu (손자 클래스)

📝 공통 정보는 부모 클래스에, 진화하면서 생기는 속성은 자식 클래스에 작성합니다.


🧪 6.2 상속

👪 "피츄에서 피카츄로!" 클래스 확장하기

public class Pokemon {
    String name;
    String type;

    public void introduce() {
        System.out.println("나는 " + name + ", 타입은 " + type + "!");
    }
}

public class Pikachu extends Pokemon {
    int level;

    public void thunderbolt() {
        System.out.println(name + "의 10만 볼트!");
    }
}

📝 Pikachu는 Pokemon을 상속받아 levelthunderbolt를 추가합니다.


🐣 "부화 과정" 생성자 호출 순서

public class Pokemon {
    public Pokemon() {
        System.out.println("포켓몬이 태어났다!");
    }
}

public class Pikachu extends Pokemon {
    public Pikachu() {
        System.out.println("피카츄가 태어났다!");
    }
}

출력 순서:

포켓몬이 태어났다!
피카츄가 태어났다!

🚀 상속 효과 실감하기

Pikachu pika = new Pikachu();
pika.name = "피카츄";
pika.type = "전기";
pika.level = 15;

pika.introduce();     // 부모 메서드
pika.thunderbolt();   // 자식 메서드

📜 6.3 상속 규칙

🧠 "○○은 ○○이다" Is-a 관계

"피카츄는 포켓몬이다" → 상속 가능
"포켓몬은 피카츄이다" → ❌ 역상속 불가


🚫 "전설은 복제 불가!" 상속 금지 클래스

public final class Mewtwo extends Pokemon {
    // 상속 불가 클래스
}

📝 final 클래스는 더 이상 상속할 수 없습니다.


🔒 "봉인된 특성" Sealed 클래스 (Java 17+)

public sealed class Pokemon permits Pikachu, Eevee {}

Pokemon은 Pikachu와 Eevee만 상속 가능


🧙 "전수된 기술" 상속 불가 멤버

  • private 필드/메서드 → 자식 클래스에서 접근 불가
  • final 메서드 → 오버라이드 불가

🎯 6.4 정리와 테스트

📘 상속 요약

개념 설명
상속 (extends) 클래스 기능을 이어받음
부모 클래스 공통 기능 보유
자식 클래스 개별 기능 추가
Is-a 관계 ○○는 ××이다
final 상속 금지
sealed 상속 가능한 클래스 제한 (Java 17+)

💻 종합 예제 코드

public class Pokemon {
    String name;
    String type;

    public void introduce() {
        System.out.println("나는 " + name + ", 타입은 " + type + "!");
    }
}

public class Pikachu extends Pokemon {
    int level;

    public Pikachu(String name, int level) {
        this.name = name;
        this.type = "전기";
        this.level = level;
    }

    public void thunderbolt() {
        System.out.println(name + "의 10만 볼트! 효과는 굉장했다!");
    }
}

public class Main {
    public static void main(String[] args) {
        Pikachu pika = new Pikachu("피카츄", 20);
        pika.introduce();
        pika.thunderbolt();
    }
}

🧩 이 예제로 상속, 생성자 호출 순서, 메서드 오버라이드의 흐름을 익힐 수 있습니다!


🌳 제7장 포켓몬 가계의 미스터리! 상속 관계를 마스터하라

🧭 7.1 상속 트리

🧬 "포켓몬 진화 가계도" 상속 트리 전체 구조

포켓몬은 진화 계통을 가지며, Java에서도 상속 트리로 표현할 수 있습니다.

예) 나옹 → 나이킹 (지역 진화)

Pokemon
├── Meowth
│   └── Perrserker
└── Eevee
    ├── Vaporeon
    ├── Jolteon
    └── Flareon

🧬 모든 포켓몬의 조상, Object 클래스

Java의 모든 클래스는 암묵적으로 Object 클래스를 상속합니다.

public class Pikachu {
    // Object 클래스의 toString(), equals() 사용 가능
}

🔗 7.2 생성자의 연결

👶 부모 → 자식으로 이어지는 생성자 호출

public class Pokemon {
    public Pokemon(String name) {
        System.out.println(name + " 이(가) 태어났습니다!");
    }
}

public class Eevee extends Pokemon {
    public Eevee() {
        super("이브이");
        System.out.println("이브이 준비 완료!");
    }
}

출력 결과:

이브이 이(가) 태어났습니다!
이브이 준비 완료!

❓ super() 생략 시 행동

부모 클래스에 인자가 없는 기본 생성자가 있으면 super()는 생략 가능
단, 부모 생성자에 매개변수가 있다면 반드시 명시 필요!


📁 7.3 여러 클래스를 하나의 파일에 정의하기

public class Pokemon {
    String name;
    public void greet() {
        System.out.println("안녕! 나는 " + name + "!");
    }
}

class Pikachu extends Pokemon {
    public Pikachu() {
        name = "피카츄";
    }
}

📝 파일명이 Pokemon.java일 경우, public 클래스는 하나만 존재해야 하며 나머지는 public 없이 작성


🛡 7.4 protected 접근자

🏠 "가족에게만 보이는 특성" protected의 특별한 힘

public class Pokemon {
    protected String name; // 같은 패키지와 자식 클래스에서 접근 가능
}

⚠️ 주의사항

  • 외부 패키지에서는 접근 불가
  • public, private와 구분하여 정확히 사용

🌐 접근 제어자 정리

접근자 동일 클래스 동일 패키지 자식 클래스 외부 클래스
public
protected ×
(default) × ×
private × × ×

🎯 7.5 정리와 테스트

🧾 7장 요약: Java의 상속 가계도 완전 이해!

개념 설명
상속 트리 클래스 간 부모-자식 구조
Object 클래스 모든 클래스의 조상
super() 부모 생성자 호출
protected 같은 패키지, 자식 클래스 접근 가능

💻 종합 예제 코드

public class Pokemon {
    protected String name;

    public Pokemon(String name) {
        this.name = name;
        System.out.println(name + " 이(가) 태어났습니다!");
    }

    public void greet() {
        System.out.println("안녕하세요! 저는 " + name + " 입니다!");
    }
}

class Pikachu extends Pokemon {
    public Pikachu() {
        super("피카츄");
        System.out.println("피카츄 준비 완료!");
    }

    public void thunderbolt() {
        System.out.println(name + " 의 10만 볼트!");
    }
}

public class Main {
    public static void main(String[] args) {
        Pikachu pika = new Pikachu();
        pika.greet();
        pika.thunderbolt();
    }
}

🎉 이 장에서는 상속 구조, protected, 클래스 파일 내 동시 정의 등을 모두 마스터할 수 있습니다!


🌀 제8장 포켓몬의 변신술! 참조의 자동 형변환

🪄 8.1 참조의 자동 형변환

🔁 "메타몽의 변신" 자식 → 부모 클래스 자동 형변환

Java에서는 자식 클래스의 인스턴스를 부모 클래스 타입으로 자동 형변환할 수 있습니다.

Pokemon pika = new Pikachu("피카츄", 20);
pika.introduce(); // 부모 메서드는 사용 가능

📝 이처럼 Pikachu 타입 인스턴스를 Pokemon 타입으로 저장 → 업캐스팅


🧱 8.2 업캐스트와 다운캐스트

⬆️ 업캐스트 (자동)

Pokemon poke = new Pikachu("피카츄", 20);

⬇️ 다운캐스트 (명시적)

Pikachu pika = (Pikachu) poke;
pika.thunderbolt(); // 자식 클래스의 메서드 사용 가능

⚠️ poke가 Pikachu가 아닐 경우, ClassCastException 발생


🔍 8.3 instanceof 연산자

🧪 "진짜 피카츄인가?" instanceof로 타입 확인

if (poke instanceof Pikachu) {
    Pikachu pika = (Pikachu) poke;
    pika.thunderbolt();
}

📝 안전한 다운캐스트를 위한 타입 체크 필수


🧠 8.4 switch를 이용한 타입 판별 (Java 14~)

switch (poke) {
    case Pikachu p -> p.thunderbolt();
    case Eevee e -> e.adapt();
    default -> System.out.println("알 수 없는 포켓몬");
}

📝 패턴 매칭 switch를 활용하면 코드가 간결해집니다


🎯 8.5 정리와 테스트

📘 변신의 기술 요약

용어 설명
업캐스트 자식 → 부모 (자동)
다운캐스트 부모 → 자식 (명시적)
instanceof 타입 안전 확인
switch 패턴 Java 14+ 타입 분기 가능

💻 종합 예제 코드

public class Pokemon {
    protected String name;

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

    public void introduce() {
        System.out.println("나는 " + name + " 입니다!");
    }
}

class Pikachu extends Pokemon {
    private int level;

    public Pikachu(String name, int level) {
        super(name);
        this.level = level;
    }

    public void thunderbolt() {
        System.out.println(name + " 의 10만 볼트! 레벨: " + level);
    }
}

class Eevee extends Pokemon {
    public Eevee(String name) {
        super(name);
    }

    public void adapt() {
        System.out.println(name + " 는 다양한 타입으로 진화할 수 있다!");
    }
}

public class Main {
    public static void main(String[] args) {
        Pokemon poke1 = new Pikachu("피카츄", 25); // 업캐스트
        Pokemon poke2 = new Eevee("이브이");

        if (poke1 instanceof Pikachu) {
            Pikachu pika = (Pikachu) poke1;
            pika.thunderbolt();
        }

        switch (poke2) {
            case Pikachu p -> p.thunderbolt();
            case Eevee e -> e.adapt();
            default -> System.out.println("알 수 없는 포켓몬");
        }
    }
}

🧩 이 예제로 업캐스트, 다운캐스트, instanceof, switch 패턴을 마스터할 수 있습니다!


🎭 제9장 하나의 기술로 다양한 효과! 다형성(Polymorphism)

💡 9.1 오버로드

🧠 "같은 이름, 다른 효과" 오버로드의 원리

Java에서는 같은 이름의 메서드를 매개변수의 수나 타입이 다르면 여러 개 정의할 수 있습니다.

public void attack(String move) {
    System.out.println("「" + move + "」을(를) 사용했다!");
}

public void attack(String move, int times) {
    System.out.println("「" + move + "」을(를) " + times + "번 연속 사용했다!");
}

🔁 9.2 오버라이드

🔄 "진화로 기술이 강화되었다!" 오버라이드의 개념

오버라이드는 부모 클래스의 메서드를 자식 클래스에서 재정의하는 것입니다.

public class Pokemon {
    public void attack() {
        System.out.println("기본 공격!");
    }
}

public class Pikachu extends Pokemon {
    @Override
    public void attack() {
        System.out.println("피카츄의 10만 볼트!");
    }
}

📝 @Override는 재정의임을 명확히 하여 실수를 방지합니다.


🌀 9.3 다형성 (Polymorphism)

🎨 "같은 기술, 다른 효과" 다형성의 마법

다형성이란 부모 클래스 타입으로 자식 클래스 메서드를 실행할 수 있는 기능입니다.

Pokemon poke = new Pikachu();
poke.attack(); // 실제로는 Pikachu의 attack() 실행됨

📝 호출 시점의 타입이 아닌 실제 인스턴스 타입에 따라 동작 → 동적 바인딩


✨ 트레이너가 기술을 사용할 때

public class Trainer {
    public void usePokemon(Pokemon p) {
        p.attack();
    }
}

포켓몬의 종류와 관계없이 attack() 호출 가능


🎯 9.4 정리와 테스트

✅ 다형성 요약 표

개념 설명
오버로드 같은 이름, 다른 인자
오버라이드 부모 메서드 재정의
다형성 부모 타입으로 자식 메서드 실행
동적 바인딩 실행 시점에 맞는 메서드 호출

💻 종합 예제 코드

public class Pokemon {
    public void attack() {
        System.out.println("기본 공격!");
    }

    public void attack(String move) {
        System.out.println("「" + move + "」을(를) 사용했다!");
    }

    public void attack(String move, int times) {
        System.out.println("「" + move + "」을(를) " + times + "번 사용했다!");
    }
}

class Pikachu extends Pokemon {
    @Override
    public void attack() {
        System.out.println("피카츄의 10만 볼트!");
    }
}

class Eevee extends Pokemon {
    @Override
    public void attack() {
        System.out.println("이브이의 스피드스타!");
    }
}

class Trainer {
    public void usePokemon(Pokemon p) {
        p.attack();
    }
}

public class Main {
    public static void main(String[] args) {
        Trainer ash = new Trainer();

        Pokemon pika = new Pikachu();
        Pokemon eevee = new Eevee();

        ash.usePokemon(pika);   // 피카츄의 기술
        ash.usePokemon(eevee);  // 이브이의 기술

        pika.attack("아이언 테일");      // 오버로드 예시
        pika.attack("전광석화", 2);      // 오버로드 예시
    }
}

🧩 이 코드로 오버로드, 오버라이드, 다형성 전부를 실습할 수 있습니다!


🦄 제10장 환상의 포켓몬의 비밀! 추상 클래스의 세계

🧩 10.1 추상 클래스란?

👻 "도감에 없는 미지의 포켓몬" 추상 클래스의 정의

추상 클래스 (abstract class)는 불완전한 설계도입니다.
직접 인스턴스화할 수 없으며, 자식 클래스에서 구현을 완성해야 합니다.

public abstract class Pokemon {
    String name;
    String type;

    public void introduce() {
        System.out.println("나는 " + name + "! 타입은 " + type + "!");
    }

    public abstract void specialMove(); // 추상 메서드
}

📝 추상 메서드는 몸체가 없으며, 반드시 자식 클래스에서 정의 필요


🧬 10.2 추상 클래스 상속

🌟 "전설에서 현실로" 추상 메서드 구현

public class Mew extends Pokemon {
    public Mew() {
        name = "뮤";
        type = "에스퍼";
    }

    @Override
    public void specialMove() {
        System.out.println("뮤의 사이코키네시스!");
    }
}

📝 자식 클래스에서 반드시 specialMove()를 오버라이드 해야 함


✨ 중간 추상화 계층 만들기

public abstract class LegendaryPokemon extends Pokemon {
    public abstract void summon(); // 추가 추상 메서드
}

🗺 10.3 추상 클래스 다이어그램

<<abstract>> Pokemon
    + introduce()
    + specialMove() ← abstract

       ▲
       |
     Mew (specialMove() 구현)

📝 <<abstract>>는 추상 클래스를 나타냅니다


🎯 10.4 정리와 테스트

✅ 요약 표

항목 설명
abstract class 불완전한 설계도, 직접 생성 불가
abstract method 자식 클래스에서 구현 필요
강제 구현 추상 메서드가 있으면 반드시 구현
중간 추상화 추상 클래스끼리도 상속 가능

💻 종합 예제 코드

public abstract class Pokemon {
    protected String name;
    protected String type;

    public void introduce() {
        System.out.println("나는 " + name + "! 타입은 " + type + "!");
    }

    public abstract void specialMove();
}

class Mew extends Pokemon {
    public Mew() {
        this.name = "뮤";
        this.type = "에스퍼";
    }

    @Override
    public void specialMove() {
        System.out.println(name + "의 사이코키네시스!");
    }
}

public class Main {
    public static void main(String[] args) {
        Pokemon mystery = new Mew(); // 추상 클래스 타입으로 인스턴스 사용
        mystery.introduce();
        mystery.specialMove();
    }
}

🧩 이 예제로 추상 클래스, 오버라이드, 다형성까지 경험할 수 있습니다!


🔗 제11장 포켓몬의 타입과 능력! 인터페이스의 힘

💡 11.1 인터페이스란?

🔍 "비행 타입", "물 타입" → 인터페이스 정의

Java의 interface기능의 계약서입니다.
공통된 능력을 여러 클래스가 구현할 수 있도록 합니다.

public interface Flyable {
    void fly(); // 비행 타입이면 반드시 구현
}

🧪 "복수 타입을 가진 포켓몬" → 클래스에 인터페이스 구현

public class Charizard implements Flyable {
    @Override
    public void fly() {
        System.out.println("리자몽이 하늘을 날았다!");
    }
}

📝 implements 키워드로 "이 클래스는 날 수 있다"고 명시


✨ 인터페이스 메서드는 모두 public abstract

즉, 수정 불가능하고 구현 강제됨
공통된 기능을 동일하게 사용하도록 설계된 구조


🔁 11.2 인터페이스 타입으로 형변환

🔄 "타입으로써의 포켓몬" 인터페이스 타입 사용

Flyable flyingPokemon = new Charizard();
flyingPokemon.fly(); // 리자몽의 fly() 호출됨

🎯 "물 타입으로 사용" WaterType 예시

public interface WaterType {
    void surf();
}

public class Vaporeon implements WaterType {
    @Override
    public void surf() {
        System.out.println("샤미드가 파도를 탄다!");
    }
}

🎭 11.3 인터페이스 기반 다형성

🧬 "같은 기술 이름, 다양한 클래스" 다형성 실현

public void useFly(Flyable f) {
    f.fly();
}

📝 클래스와 무관하게 Flyable 인터페이스만 구현되어 있으면 실행 가능


🧪 "실전: 타입별 기술 효과"

Flyable f1 = new Charizard();
Flyable f2 = new Pidgeot();

f1.fly(); // 리자몽
f2.fly(); // 피죤투

🌐 11.4 인터페이스 상속

🔗 "복합 타입 포켓몬" 다중 상속 구현

public interface FlyingWaterType extends Flyable, WaterType {
    void dive();
}

🧠 인터페이스도 상속된다!

public class Gyarados implements FlyingWaterType {
    @Override
    public void fly() {
        System.out.println("갸라도스가 날아올랐다!");
    }

    @Override
    public void surf() {
        System.out.println("갸라도스가 파도를 탔다!");
    }

    @Override
    public void dive() {
        System.out.println("갸라도스가 잠수했다!");
    }
}

🎯 11.5 정리와 테스트

✅ 요약 표

항목 설명
interface 기능 계약, 타입과 유사
implements 인터페이스 구현
다중 구현 여러 타입 동시 보유 가능
다형성 클래스 구분 없이 기능 호출 가능

💻 종합 예제 코드

public interface Flyable {
    void fly();
}

public interface WaterType {
    void surf();
}

public class Charizard implements Flyable {
    @Override
    public void fly() {
        System.out.println("리자몽이 하늘을 날았다!");
    }
}

public class Vaporeon implements WaterType {
    @Override
    public void surf() {
        System.out.println("샤미드가 파도를 탔다!");
    }
}

public class Gyarados implements Flyable, WaterType {
    @Override
    public void fly() {
        System.out.println("갸라도스가 날아올랐다!");
    }

    @Override
    public void surf() {
        System.out.println("갸라도스가 파도를 쳤다!");
    }
}

public class Main {
    public static void main(String[] args) {
        Flyable f = new Charizard();
        WaterType w = new Vaporeon();
        Flyable fw = new Gyarados();

        f.fly();
        w.surf();
        fw.fly();

        if (fw instanceof WaterType water) {
            water.surf(); // 갸라도스도 surf 가능
        }
    }
}

🧩 이 장에서는 인터페이스, 다형성, 다중 구현을 완전히 이해할 수 있습니다!

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?