extends, implements, this, super 정리

revo·2026년 2월 8일

자바

목록 보기
4/30

상속과 생성자를 헷갈리지 않기 위한 핵심 정리

자바에서 객체지향을 처음 공부할 때 가장 헷갈렸던 부분이 extends, implements, this, super였다.
문법은 외우기 쉬운데, 왜 이런 문법이 필요한지, 언제 써야 하는지가 명확하지 않으면 코드가 계속 꼬인다.

이 글은 문법 나열이 아니라, “내가 왜 여기서 헷갈렸는지 → 그래서 무엇을 기준으로 이해해야 하는지”를 중심으로 정리한다.


1. extends는 클래스 상속이다

extends부모 클래스의 상태와 동작을 물려받는 것이다.

class Animal {
    void eat() {}
}

class Dog extends Animal {
    void bark() {}
}

여기서 핵심은 문법이 아니라 관계다.

  • Dog is an Animal → 자연스러움
  • Animal is a Dog → 말이 안 됨

👉 extendsIS-A 관계를 표현할 때만 써야 한다.

헷갈렸던 포인트

  • “기능이 비슷하니까 상속해도 되지 않나?”
    → 아니다. 기능이 아니라 정체성 기준이다.

2. implements는 인터페이스 구현이다

implements“이 클래스가 이 역할을 수행할 수 있다”는 약속이다.

interface Flyable {
    void fly();
}

class Bird implements Flyable {
    @Override
    public void fly() {}
}

여기서 Bird는:

  • Flyable 이다 X
  • Flyable을 할 수 있다 O

👉 implementsCAN-DO 관계다.


3. 인터페이스 메서드는 왜 public이어야 하는가

인터페이스 메서드는 작성할 때 public을 생략해도 된다.

interface Flyable {
    void fly();
}

하지만 이건 실제로는 다음과 같다.

public abstract void fly();

그래서 구현 클래스에서는 반드시 public을 붙여야 한다.

class Bird implements Flyable {
    public void fly() {}  // O
}
class Bird implements Flyable {
    void fly() {}         // X
}

핵심 이유

  • 오버라이딩 시 접근 제한자는 더 좁아질 수 없다
  • 인터페이스는 외부와의 공개 계약이기 때문에 무조건 public

4. 인터페이스 메서드에 파라미터가 있으면?

너무 정상적인 상황이다.

interface Shape {
    int area(int width, int height);
}

이 한 줄이 의미하는 계약은 명확하다.

“이 역할을 구현하는 클래스는 int 두 개를 받아 int 하나를 반환하는 area를 제공해야 한다”

반드시 지켜야 하는 것

  • 메서드 이름
  • 파라미터 타입 / 개수 / 순서
  • 반환 타입
  • 접근 제한자 (public)

파라미터 이름은 계약이 아니다.


5. Shape s = new Rectangle(); 을 왜 쓰는가

Shape s = new Rectangle();
s.area(10, 5);

이 문장은 단순한 문법이 아니다.

👉 “구현이 아니라 역할에 의존하겠다”는 선언이다.

왜 중요한가

  • Rectangle → Triangle → Circle 로 바뀌어도
  • 사용하는 쪽 코드는 안 바뀐다
Shape s = new Triangle();
Shape s = new Rectangle();

이게 바로 다형성이고,
if-else를 없애는 객체지향의 핵심이다.


6. super는 부모 객체를 가리킨다

super는 부모 클래스가 아니라 부모 객체다.

사용 목적은 딱 세 가지

  1. super.필드
  2. super.메서드()
  3. super() → 부모 생성자 호출
class Parent {
    int x = 10;
}

class Child extends Parent {
    int x = 20;

    void print() {
        System.out.println(super.x); // 10
    }
}

7. 생성자에서 super()는 왜 중요한가

자식 객체를 만들 때 부모가 먼저 완성돼야 한다.

class Child extends Parent {
    Child() {
        super(); // 생략돼 있어도 자동 호출
    }
}

중요한 규칙

  • super()는 생성자의 첫 줄
  • 부모 기본 생성자가 없으면 반드시 명시

8. this()는 같은 클래스의 다른 생성자 호출이다

this();
this("kim");
this("kim", 20);

this()생성자 오버로딩을 위한 도구다.

왜 쓰는가

  • 생성자 중복 코드 제거
  • 초기화 로직을 한 곳에 모으기
class Person {
    Person() {
        this("guest", 0);
    }

    Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

9. this()는 어떻게 생성자를 고르는가

전달한 인자의 타입과 시그니처가 정확히 일치하는 생성자를
컴파일 타임에 선택한다

  • 값 X
  • 타입 O
this(10);      // int 생성자
this("kim");  // String 생성자

모호하면 컴파일 에러가 난다.


10. this()와 super()의 관계 정리

  • this() → 같은 클래스 생성자
  • super() → 부모 클래스 생성자
  • 둘 다 생성자 첫 줄
  • 동시에 사용 불가

실제 흐름은 항상 이렇다.

this() → 다른 생성자 → super() → 부모 생성자

마무리 정리 한 문장

  • extends → 정체성 상속 (IS-A)
  • implements → 역할 구현 (CAN-DO)
  • super → 부모 객체 접근
  • this() → 생성자 중복 제거용 도구
  • 생성자 선택은 타입 기준, 컴파일 타임

0개의 댓글