-
Notifications
You must be signed in to change notification settings - Fork 18
260616_11_유재우 #53
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: student/11_유재우
Are you sure you want to change the base?
260616_11_유재우 #53
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,196 @@ | ||
| # 2026-06-16 자바 학습 정리 : 상속 | ||
|
|
||
| ## 오늘 배운 내용 | ||
|
|
||
| - **상속(inheritance)** | ||
| - **오버라이드(override)** | ||
|
|
||
| ## 기억할 것 | ||
|
|
||
| - java의 상속은 `extends` 키워드를 사용한다. | ||
| - JUnit의 `@DisplayName`은 테스트 결과 창에서 사람이 읽기 쉬운 이름을 표시하기 위한 어노테이션이다. | ||
| - 메서드 오버라이딩에서 java는 기본이 가상 메서드 이고 c++ `Virtual` 키워드를 붙여야한다. | ||
|
|
||
| ### 코드 예시 ( java ) | ||
|
|
||
| ```java | ||
| // 부모 클래스 | ||
| class Wizard { | ||
| public void heal() { | ||
| System.out.println("일반 힐!"); | ||
| } | ||
| } | ||
|
|
||
| // 자식 클래스 | ||
| class GreatWizard extends Wizard { | ||
| @Override // 오버라이드 명시 (생략 가능하지만 가독성을 위해 필수) | ||
| public void heal() { | ||
| System.out.println("대마법사의 슈퍼 힐!"); | ||
| } | ||
| } | ||
|
|
||
| public class Main { | ||
| public static void main(String[] args) { | ||
| // [핵심 상황] 부모 타입 변수에 자식 객체를 대입! | ||
| Wizard wizard = new GreatWizard(); | ||
|
|
||
| wizard.heal(); | ||
| // 출력 결과: "대마법사의 슈퍼 힐!" (알아서 알맹이를 찾아감) | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| ## C++ | ||
|
|
||
| ### 가상메서드 X | ||
|
|
||
| ```cpp | ||
| #include <iostream> | ||
|
|
||
| class Wizard { | ||
| public: | ||
| // ★ virtual이 없습니다! | ||
| void heal() { | ||
| std::cout << "일반 힐!\n"; | ||
| } | ||
| }; | ||
|
|
||
| class GreatWizard : public Wizard { | ||
| public: | ||
| void heal() { | ||
| std::cout << "대마법사의 슈퍼 힐!\n"; | ||
| } | ||
| }; | ||
|
|
||
| int main() { | ||
| // 부모 그릇에 자식 알맹이를 넣음 | ||
| Wizard* wizard = new GreatWizard(); | ||
|
|
||
| // [결과] C++은 포인터가 Wizard니까 Wizard의 함수를 실행해버림 | ||
| wizard->heal(); // 출력: 일반 힐! (자식의 슈퍼 힐이 묻힘) | ||
|
|
||
| return 0; | ||
| } | ||
| ``` | ||
|
|
||
| ### 가상메서드 O | ||
|
|
||
| ```cpp | ||
| #include <iostream> | ||
|
|
||
| class Wizard { | ||
| public: | ||
| // ★ virtual을 붙여서 자식이 오버라이딩할 길을 열어줍니다! | ||
| virtual void heal() { | ||
| std::cout << "일반 힐!\n"; | ||
| } | ||
| }; | ||
|
|
||
| class GreatWizard : public Wizard { | ||
| public: | ||
| // 부모가 virtual이면 자식은 자동으로 virtual이 됩니다. | ||
| void heal() override { | ||
| std::cout << "대마법사의 슈퍼 힐!\n"; | ||
| } | ||
| }; | ||
|
|
||
| int main() { | ||
| // 부모 그릇에 자식 알맹이를 넣음 | ||
| Wizard* wizard = new GreatWizard(); | ||
|
|
||
| // [결과] 부모에 virtual이 있으므로 진짜 알맹이인 GreatWizard의 함수를 실행함 | ||
| wizard->heal(); // 출력: 대마법사의 슈퍼 힐! (정상 작동) | ||
|
|
||
| return 0; | ||
| } | ||
| ``` | ||
|
|
||
| ## 실습 코드 | ||
|
|
||
| ```java | ||
| package com.survivalcoding; | ||
|
|
||
| import org.junit.jupiter.api.BeforeEach; | ||
| import org.junit.jupiter.api.DisplayName; | ||
| import org.junit.jupiter.api.Test; | ||
|
|
||
| import static org.junit.jupiter.api.Assertions.assertEquals; | ||
|
|
||
| class GameTest { | ||
|
|
||
| private Hero targetHero; | ||
| private Wizard wizard; | ||
| private GreatWizard greatWizard; | ||
|
|
||
| @BeforeEach | ||
| void setUp() { | ||
| targetHero = new Hero("전사", 50, 100); | ||
| wizard = new Wizard("일반법사", 50, 50, 30, 50); | ||
| greatWizard = new GreatWizard("대법사", 60, 60, 60, 100); | ||
| } | ||
|
|
||
| @Test | ||
| @DisplayName("일반 마법사가 힐을 하면 대상의 HP가 20 오르고 마나가 10 깎여야 한다") | ||
| void wizardHealTest() { | ||
| wizard.heal(targetHero); | ||
|
|
||
| assertEquals(70, targetHero.getHp(), "전사의 HP는 50에서 20이 더해져 70이 되어야 합니다."); | ||
| } | ||
|
|
||
| @Test | ||
| @DisplayName("대마법사가 슈퍼힐을 쓰면 대상의 HP가 최대치로 차고 마나가 50 깎여야 한다") | ||
| void greatWizardSuperHealTest() { | ||
| greatWizard.SuperHeal(targetHero); | ||
|
|
||
| assertEquals(100, targetHero.getHp(), "슈퍼 힐을 받으면 최대 체력인 100이 되어야 합니다."); | ||
| } | ||
|
|
||
| @Test | ||
| @DisplayName("마나가 부족하면 힐이 나가지 않고 체력도 그대로여야 한다") | ||
| void outOfManaTest() { | ||
| Wizard oomWizard = new Wizard("마나없는법사", 50, 50, 5, 50); | ||
|
|
||
| oomWizard.heal(targetHero); | ||
|
|
||
| assertEquals(50, targetHero.getHp(), "마나가 부족하므로 타겟의 HP는 변하면 안 됩니다."); | ||
| } | ||
|
|
||
| @Test | ||
| @DisplayName("체력을 치유했을 때 최대 체력(MaxHP)을 초과할 수 없다") | ||
| void hpNotOverMaxHpTest() { | ||
| Hero highHpHero = new Hero("피통전사", 90, 100); | ||
|
|
||
| wizard.heal(highHpHero); | ||
|
|
||
| assertEquals(100, highHpHero.getHp(), "치유량의 총합이 MaxHP를 넘어가면 MaxHP로 고정되어야 합니다."); | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| ## 어려웠던 점 | ||
|
|
||
| - 오버라이딩 인식 차이: Java에서는 부모 타입 변수에 자식 객체를 담아도 알아서 자식 메서드가 호출되지만, C++에서는 부모 포인터 타입을 기준으로 함수를 실행해 버려 자식 메서드가 묻히는 정적 바인딩 현상을 | ||
| 직접 코드로 비교하며 개념을 정립하는 과정이 까다로웠다. | ||
| - JUnit 테스트 작성 중 `@DisplayName`이 적용되지 않는 것처럼 보여 원인을 찾는 데 시간이 걸렸다. | ||
|
|
||
| ## 해결 방법 | ||
|
|
||
| - C++의 가상 함수 테이블(vtable) 구조 이해: C++ 부모 클래스에 virtual 키워드를 붙이면 컴퓨터가 내부적으로 '진짜 알맹이 객체'를 찾아갈 수 있도록 이정표(가상 함수 테이블)를 세워 동적 | ||
| 바인딩을 유도한다는 원리를 깨달으며 두 언어의 차이를 완벽히 이해했다. | ||
| - IntelliJ가 테스트를 Gradle Runner로 실행하고 있어 @DisplayName이 보이지 않았음을 확인했다. | ||
| - IntelliJ 설정에서 | ||
|
|
||
| ``` | ||
| 설정 | ||
| └─ 빌드, 실행, 배포 | ||
| └─ 빌드 도구 | ||
| └─ Gradle | ||
| └─ 다음을 사용하여 테스트 실행 | ||
| Gradle → IntelliJ IDEA | ||
| ``` | ||
|
|
||
| 로 변경하여 테스트 결과 창에서 `@DisplayName`을 확인할 수 있었다. | ||
|
|
||
| ## 내일 더 공부할 것 | ||
|
|
||
| - 객체지향 프로그래밍(OOP)의 핵심을 이루는 4대 원칙 언어별 차이점 | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| package com.survivalcoding; | ||
|
|
||
| public class GreatWizard extends Wizard { | ||
|
|
||
| public GreatWizard(String name, int hp, int maxhp, int mp, int maxmp) { | ||
| super(name, hp, maxhp, mp, maxmp); | ||
| } | ||
|
|
||
| @Override | ||
| public void heal(Hero hero) { | ||
| if (mp >= 5) { | ||
| mp -= 5; | ||
| hero.incrementHP(25); | ||
| System.out.printf("대마법사의 강력한 힐! %s HP : %d\n", hero.getName(), hero.getHp()); | ||
| } else { | ||
| System.out.println("마나가 부족합니다."); | ||
| } | ||
| } | ||
|
|
||
| public void SuperHeal(Hero hero) { | ||
| if (mp >= 50) { | ||
| mp -= 50; | ||
| hero.incrementHP(hero.getMaxhp()); // 최대 체력만큼 힐 | ||
| System.out.printf("슈퍼 힐을 시전했습니다. %s HP : %d\n", hero.getName(), hero.getHp()); | ||
| } else { | ||
| System.out.println("마나가 부족합니다."); | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,11 +1,37 @@ | ||||||||||||||||||||||||||||
| package com.survivalcoding; | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| public class Hero { | ||||||||||||||||||||||||||||
| String name; | ||||||||||||||||||||||||||||
| int hp; | ||||||||||||||||||||||||||||
| private String name; | ||||||||||||||||||||||||||||
| private int hp; | ||||||||||||||||||||||||||||
| private int maxhp; | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| void attack() { | ||||||||||||||||||||||||||||
| // sout | ||||||||||||||||||||||||||||
| System.out.println("공격했다"); | ||||||||||||||||||||||||||||
| public Hero(String name, int hp, int maxhp) { | ||||||||||||||||||||||||||||
| this.name = name; | ||||||||||||||||||||||||||||
| this.hp = hp; | ||||||||||||||||||||||||||||
| this.maxhp = maxhp; | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
Comment on lines
+8
to
12
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 생성자에서 HP 불변식( 현재는 생성 시 제안 수정안 public Hero(String name, int hp, int maxhp) {
- this.name = name;
- this.hp = hp;
- this.maxhp = maxhp;
+ if (hp < 0 || maxhp < 0) {
+ throw new IllegalArgumentException("hp와 maxhp는 0 이상이어야 합니다.");
+ }
+ this.name = name;
+ this.maxhp = maxhp;
+ this.hp = Math.min(hp, maxhp);
}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| public void attack() { | ||||||||||||||||||||||||||||
| System.out.println(name + "이(가) 공격했다!"); | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| public void incrementHP(int amount) { | ||||||||||||||||||||||||||||
| if (amount + hp > maxhp) { | ||||||||||||||||||||||||||||
| hp = maxhp; | ||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||
| hp += amount; | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| public String getName() { | ||||||||||||||||||||||||||||
| return name; | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| public int getHp() { | ||||||||||||||||||||||||||||
| return hp; | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| public int getMaxhp() { | ||||||||||||||||||||||||||||
| return maxhp; | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| package com.survivalcoding; | ||
|
|
||
| public class Wizard extends Hero { | ||
| protected int mp; | ||
| private int maxmp; | ||
|
|
||
| public Wizard(String name, int hp, int maxhp, int mp, int maxmp) { | ||
| super(name, hp, maxhp); | ||
| this.mp = mp; | ||
| this.maxmp = maxmp; | ||
| } | ||
|
|
||
| public void heal(Hero hero) { | ||
| if (mp >= 10) { | ||
| mp -= 10; | ||
| hero.incrementHP(20); | ||
| System.out.printf("힐을 시전했습니다. %s HP : %d\n", hero.getName(), hero.getHp()); | ||
| } else { | ||
| System.out.println("마나가 부족합니다."); | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,57 @@ | ||
| package com.survivalcoding; | ||
|
|
||
| import org.junit.jupiter.api.BeforeEach; | ||
| import org.junit.jupiter.api.DisplayName; | ||
| import org.junit.jupiter.api.Test; | ||
|
|
||
| import static org.junit.jupiter.api.Assertions.assertEquals; | ||
|
|
||
| class GameTest { | ||
|
|
||
| private Hero targetHero; | ||
| private Wizard wizard; | ||
| private GreatWizard greatWizard; | ||
|
|
||
| @BeforeEach | ||
| void setUp() { | ||
| targetHero = new Hero("전사", 50, 100); | ||
| wizard = new Wizard("일반법사", 50, 50, 30, 50); | ||
| greatWizard = new GreatWizard("대법사", 60, 60, 60, 100); | ||
| } | ||
|
|
||
| @Test | ||
| @DisplayName("일반 마법사가 힐을 하면 대상의 HP가 20 오르고 마나가 10 깎여야 한다") | ||
| void wizardHealTest() { | ||
| wizard.heal(targetHero); | ||
|
|
||
| assertEquals(70, targetHero.getHp(), "전사의 HP는 50에서 20이 더해져 70이 되어야 합니다."); | ||
| } | ||
|
|
||
| @Test | ||
| @DisplayName("대마법사가 슈퍼힐을 쓰면 대상의 HP가 최대치로 차고 마나가 50 깎여야 한다") | ||
| void greatWizardSuperHealTest() { | ||
| greatWizard.SuperHeal(targetHero); | ||
|
|
||
| assertEquals(100, targetHero.getHp(), "슈퍼 힐을 받으면 최대 체력인 100이 되어야 합니다."); | ||
| } | ||
|
|
||
| @Test | ||
| @DisplayName("마나가 부족하면 힐이 나가지 않고 체력도 그대로여야 한다") | ||
| void outOfManaTest() { | ||
| Wizard oomWizard = new Wizard("마나없는법사", 50, 50, 5, 50); | ||
|
|
||
| oomWizard.heal(targetHero); | ||
|
|
||
| assertEquals(50, targetHero.getHp(), "마나가 부족하므로 타겟의 HP는 변하면 안 됩니다."); | ||
| } | ||
|
|
||
| @Test | ||
| @DisplayName("체력을 치유했을 때 최대 체력(MaxHP)을 초과할 수 없다") | ||
| void hpNotOverMaxHpTest() { | ||
| Hero highHpHero = new Hero("피통전사", 90, 100); | ||
|
|
||
| wizard.heal(highHpHero); | ||
|
|
||
| assertEquals(100, highHpHero.getHp(), "치유량의 총합이 MaxHP를 넘어가면 MaxHP로 고정되어야 합니다."); | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
코드 블록 언어를 지정해 주세요.
183행의 fenced code block에 언어 태그가 없어 markdownlint 경고가 납니다.
text같은 언어를 붙이거나, 코드 펜스를 제거하면 됩니다.🛠️ 제안 수정
🧰 Tools
🪛 markdownlint-cli2 (0.22.1)
[warning] 183-183: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
🤖 Prompt for AI Agents
Source: Linters/SAST tools