KDT 공부 일지 - 2026.01.14

김시코·2026년 1월 14일

KDT 공부 일지

목록 보기
8/27

2026년 1월 14일 수요일 - 4주차


Enum

enum의 주 목적은 도메인(값의 범위)를 제약하는것이며, 가독성 및 타입의 안전성을 확보한다.


상속, 오버라이딩, 다형성

강사님께서 상속, 오버라이딩, 다형성은 객체지향 설계의 핵심 요소이며, 이들이 서로 어떻게 연결되는지 하나라도 이해하지 못하면 이 3개의 개념을 명확히 이해하지 못하고 있는것이라고 하셨다. 그리고, 이 3가지 개념이 가장 잘 드러나는 예가 인터페이스(interface)라고 한다.

  • 사용 목적: 의존도를 낮추는 코딩을 위함.
    - 상속: 공통된 기능을 부모 클래스에 두고 재사용 하는 것. (이미 있는것을 물려받는것)
    - 다형성: 부모 타입으로 자식을 다루지만 행동은 자식을 기준으로 실행되는 것 (같은 타입처럼 다루지만 실제 행동은 다르게 하곘다)
    - 오버라이딩: 부모의 메서드를 자식에 맞게 다시 정의하는 것. (물려받긴 했지만 행동은 다르게 하겠다)
    - extends: 부모로부터 상속을 받아 확장하는 것.
    - implement: 추상 클래스 부모로부터 상속을 받아 구현을 하는 것.
  • 부모는 2개 이상이 될 수 없고 자식은 하나의 부모만을 가져야 하며(다중상속이 불가능), 부모는 자식을 여러개 가질 수 있지만, interface의 경우에는 다중 상속이 가능하다. 하지만 implement만 가능하고, extents는 불가능 하다. (확장은 안되는데 구현은 가능)

[명명법]

  • interface: 클래스와 같이 파스칼 케이스(camelCase에서 앞 자리를 대문자로 하는것)를 쓰며, 형용사(명사 뒤에 able이 붙는 식)와 명사를 씀
  • 변수: camelCase를 따르며, 명사를 사용한다.
  • 클래스: PascalCase를 따르며, 명사를 사용한다
  • 메서드: CamelCase를 따르며, 동사를 사용한다
  • public static final을 붙이연 더 이상 변경할 수 없는 완전한 상수가 되며, 관례적으로 대문자만으로 이루어지며, 단어가 바뀌면 _를 사용한다. (소문자 사용x)
[p1.App]
package p1;

public class App {
    public static void main(String[] args) {
        // 상속 문법
        AAA aaa = new AAA();
        aaa.a1 = 10;
        aaa.a2 = 20;
        aaa.testA();

        BBB bbb = new BBB();
        bbb.b1 = 10;
        bbb.b2 = 10;
        bbb.a1 = 10;
        bbb.a2 = 20;
        bbb.testA();
        bbb.testB();
    }
}

class AAA {
    public int a1;
    public int a2;

    public void testA() {
        //...
    }
}

class BBB extends AAA {
  // AAA를 확장해서 BBB라는 클래스를 정의하고 싶다. 즉, 상속받는다는 것.
    public int b1;
    public int b2;
    public void testB() {
        // 구현부...
    }
}
[p2.App]
package p2;

public class App {
    public static void main(String[] args) {
        WorldGame worldGame = new WorldGame();

		// 이 부분이 코드를 조립시키는 부분. 즉, 다형성이다.
        // addPerson 메서드를 호출 할때 아규먼트로 Person 클래스의 메서드 대신
        // Person을 상속받고 있는 자식 클래스들의 메서드가 호출되는 것.
        worldGame.addPerson(new Student("철수"));
        worldGame.addPerson(new Student("민수"));
        worldGame.addPerson(new Police("영희"));
        worldGame.addPerson(new Doctor("수진"));
        worldGame.addPerson(new Chef("아영"));

        worldGame.start();
    }
}

class WorldGame {

    private Person[] personList = new Person[5];
    private int count = 0;

    // DI
    public void addPerson(Person person) {
        personList[count++] = person;       // 여기에 자식값도 있다
    }

    public void start() {
        System.out.println("아침이 되었습니다.");
        // 아침이 되면 모든 사람들은 일을 한다.
        for(Person person : personList) {
            person.work();
        }
        System.out.println("점심 시간이 되었습니다.");
        // 점심이 되면 모든 사람들은 점심을 먹는다.
        for(Person person : personList) {
            person.eat();
        }
        System.out.println("밤 시간이 되었습니다.");
        // 밤이 되면 모든 사람들은 잠을 잔다.
        for(Person person : personList) {
            person.sleep();
        }
    }
}

// 개념(추상) 클래스 - 상속 전용 클래스
abstract class Person {
    protected String name;

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

    // 추상 메서드: 모양만 선언이 되어 있는것을 말함.
    // 구현이 불가능하여 무조건 상속을 받는 자식 클래스가 오버라이딩 해야함
    public abstract void work();

    public void eat() {
        System.out.println("[사람] " + name + "은 밥을 먹습니다.");
    }

    public void sleep() {
        System.out.println("[사람] " + name + "은 잠을 잡니다.");
    }
}

class Student extends Person {      // 자식 클래스
    public Student(String name) {
        super(name);
    }

    public void work() {    		// 이게 메서드를 오버라이딩하는 부분
        System.out.println("[학생] " + name + "은 공부를 합니다.");
    }
}

class Police extends Person {
    public Police(String name) {
        super(name);
    }

    public void work() {
        System.out.println("[경찰] " + name + "은 범인을 잡으러 다닙니다.");
    }

    public void eat() {
        System.out.println("[경찰] 밥 먹을 시간이 없습니다. 여전히 범인을 잡습니다.");
    }
}

class Doctor extends Person {
    public Doctor(String name) {
        super(name);
    }

    public void work() {
        System.out.println("[의사] " + name + "는 환자를 돌봅니다.");
    }

    public void eat() {
        System.out.println("[의사] 응급상황을 대비해 긴장하고 급하게 밥을 먹습니다.");
    }
}

class Chef extends Person {
    public Chef(String name) {
        super(name);
    }

    public void work() {
        System.out.println("[셰프] " + name + "은 요리를 합니다.");
    }
}
[p3.App]
package p3;

public class App {
    public static void main(String[] args) {
        // 인터페이스(자바의 꽃): 상속 - 다형성 - 오버라이딩

        AAA aaa = new BBB();
          // 구현이 불가능해 생성자가 없기 때문에,
          // AAA의 인스턴스를 생성할수 없어서 다형성이 강제된다.
        aaa.test1();
          // abstract이기 때문에 문법적으로 test1이 실행된다.
    }
}

interface AAA {
    public void test1();
      // interface는 구현 불가. abstract가 생략되어 있는것 - 추상화 클래스
      // 추상화이기 때문에 알아서 오버라이딩을 써서 구현해라.
 /* public abstract void test()1;
 	void test1(); */  // 이 2개의 경우로도 쓰긴 하지만 위에걸 제일 자주 쓴다.
    public void test2();
      // 물론 구현이 안되기 때문에 생성자가 없어 인스턴스 생성을 할 수 없다.
}

class BBB implements AAA {
// extends가 아닌 implements를 쓴다. 개념적으론 상속받는것이 맞지만 extends는
// 확장한다는 뜻이 강하기 때문에 implements라는 용어가 새로 나왔다.
// 상속이긴 하지만 부모 클래스를 확장해서 사용한다는 것이 아닌.
// 추상 메서드인 부모 클래스를 구현하는 구현관계에 있다는 뜻이다.
    public void test1() {

    }

    public void test2() {

    }
}
[p4.App]
package p4;

public class App {
    public static void main(String[] args) {
        QWER qwer = new QWER();     // 얘는 그냥 인스턴스 생성
        AAA aaa = qwer; // AAA aaa = new QWER(); 랑 같음
        BBB bbb = qwer; // 이거랑 위에는 다형성

        aaa.test1();
        bbb.test2();
        // aaa는 test1만 쓸 수 있고, bbb는 test2만 쓸 수 있다.
        // aaa에는 interface 클래스 AAA만 있고, bbb에는 interface 클래스
        // BBB만 있기 때문에, 당연히 그 안에 있는것만 쓸 수 있음.

    }
}

class QWER implements AAA, BBB {
    public void test1() { }
    public void test2() { }
}

interface AAA {
    public void test1();
}

interface BBB {
    public void test2();
}
[p5.App]
package p5;

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

interface AAA {
    public static final int NUMBER_TEN = 10; // 완전한 상수 명명법 + 관례
    
    public static void qwer() {
    // interface는 인스턴스를 생성할 수 없기 때문에, 인스턴스 생성이 없이,
    // interface명으로 바로 호출이 가능한 static 메서드를 사용한다.
        System.out.println("asdasd");
    }

    default public void asdf(){
      // 상속 받는게 조금 편해지게 하기 위해서 기본값을 제공해줌.
    }

    public void test1();
}

// interface끼리는 서로 extends 상속이 된다, 묶어주는 느낌으로.
// 물론 class는 interface를 extends 할수 없고 implements로 구현만 가능하다.
interface BBB extends AAA {
    public void test2();
}

class Some implements BBB {
    public void test1() {

    }

    public void test2() {

    }
}
  • p3, p4가 중요하다고 한다.

profile
취업하고싶다...

0개의 댓글