📚 목차
- 🔹 제1장 포켓몬 도감 만들기! 클래스 설계도
- 🔹 1.1 오브젝트란?
- 🔹 1.2 클래스를 만들자
- 🔹 1.3 정리와 테스트
- 🔹 제2장 몬스터볼에서 GET! 인스턴스 생성과 사용법
- 🔹 2.1 인스턴스를 만들자
- 🔹 2.2 게터와 세터의 사용법
- 🔹 2.3 메서드를 추가하자
- 🔹 2.4 정리와 테스트
- 🔹 제3장 포켓몬의 비밀을 지켜라! 클래스의 구조
- 🔹 3.1 다른 클래스에서의 접근 제한
- 🔹 3.2 멤버의 구조
- 🔹 3.3 생성자의 구조
- 🔹 3.4 정리와 테스트
- 🔹 제4장 포켓몬을 가리켜라! 인스턴스와 참조의 비밀
- 🔹 4.1 참조란?
- 🔹 4.2 참조를 의식하자
- 🔹 4.3 완전히 불변의 클래스를 만들자!
- 🔹 4.4 참조형
- 🔹 4.5 정리와 테스트
- 🔹 제5장 오리지널 포켓몬 설계하기! 객체 모델링
- 🔹 5.1 기능을 구현하는 클래스
- 🔹 5.2 record
- 🔹 5.3 정리와 테스트
- 🔹 제6장 진화의 비밀을 밝혀라! 상속이라는 혈통
- 🔹 6.1 클래스 다이어그램
- 🔹 6.2 상속
- 🔹 6.3 상속 규칙
- 🔹 6.4 정리와 테스트
- 🔹 제7장 포켓몬 가계의 미스터리! 상속 관계를 마스터하자
- 🔹 7.1 상속 트리
- 🔹 7.2 생성자의 연결
- 🔹 7.3 여러 클래스를 하나의 파일로
- 🔹 7.4 protected 한정자
- 🔹 7.5 정리와 테스트
- 🔹 제8장 포켓몬의 변신술! 참조의 자동 형변환
- 🔹 8.1 참조의 자동 형변환
- 🔹 8.2 업캐스트와 다운캐스트
- 🔹 8.3 instanceof 연산자
- 🔹 8.4 switch에 의한 타입 판정
- 🔹 8.5 정리와 테스트
- 🔹 제9장 하나의 기술로 다양한 효과! 다형성
- 🔹 9.1 오버로드
- 🔹 9.2 오버라이드
- 🔹 9.3 다형성
- 🔹 9.4 정리와 테스트
- 🔹 제10장 환상의 포켓몬의 수수께끼! 추상 클래스의 세계
- 🔹 10.1 추상 클래스란?
- 🔹 10.2 추상 클래스 상속
- 🔹 10.3 추상 클래스 다이어그램
- 🔹 10.4 정리와 테스트
- 🔹 제11장 포켓몬의 타입과 능력! 인터페이스의 힘
- 🔹 11.1 인터페이스란
- 🔹 11.2 인터페이스형으로의 형변환
- 🔹 11.3 인터페이스에 의한 다형성
- 🔹 11.4 인터페이스 상속
- 🔹 11.5 정리와 테스트
🧩 제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 정리와 테스트
✅ 클래스의 핵심 정리
요소 | 설명 |
---|---|
클래스 | 설계도 (포켓몬의 공통 정보) |
오브젝트 | 실제로 생성된 피카츄나 파이리 등 |
속성 | 이름, 타입, 레벨 |
메서드 | 자기소개 등의 행동 |
📝 연습문제
- 자신만의 포켓몬을 생각해서
Pokemon
클래스로 표현해 보세요. -
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과 같은 포켓몬을 가리킴
📝 pika2
는 pika1
과 같은 포켓몬 인스턴스를 참조할 뿐, 새로 생성된 것이 아닙니다.
👀 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을 상속받아 level
과 thunderbolt
를 추가합니다.
🐣 "부화 과정" 생성자 호출 순서
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 가능
}
}
}
🧩 이 장에서는 인터페이스, 다형성, 다중 구현을 완전히 이해할 수 있습니다!