[CS] 자바의 정석 독서 #9 - 상속

2025. 10. 2. 01:26·언어공부/Java | Kotlin

드디어 자바와 OOP의 꽃, 상속과 다형성


상속

기존의 클래스를 재사용해 새로운 클래스를 작성하는 것이다.

 

class Child extends Parent() { }

이러면 Child 클래스는 Parent 클래스를 상속하게되며, Child가 하위클래스, Parent가 상위클래스에 속하게 된다.

 

하위클래스는 상위클래스에 속하는 모든 멤버 (인스턴스변수, 메서드 등을 포함한 모든 것) 을 상속받는다. 단, 생성자와 초기화블럭은 상속받지 않는다.

 

밴 다이어그램을 그려보면 상위클래스가 하위클래스 안에 속하는 그림을 그릴 수 있다. 하위클래스가 상속받은 것을 수정할 수도 있고, 상속받은 것에서 새로운 메서드 등도 추가할 수 있기 때문이다.

 

하위클래스가 변경되는 것은 상위클래스에 어떠한 영향도 끼치지 못하지만, 상위클래스의 변동사항은 하위클래스에 영향을 미친다. 따라서 상속이 아니라 extends, 즉 확장으로 칭하는 경우도 있다.

 

이처럼 상속을 사용하면 공통된 하나의 상위클래스에서 여러 개의 하위클래스로 분리하여 코드를 통합시키고 중복을 줄여 유지보수성과 가독성을 향상시킬 수 있다.


상속? 포함?

포함관계란 클래스의 인스턴스 변수로 다른 클래스를 선언하는 것을 말한다. 형변환이 자주 일어나는 경우 형변환 전용 컨버터 클래스를 따로 만들어두고 형변환이 필요할 때마다 인스턴스 변수로 선언해 사용하는 것처럼 특정 기능단위별로 여러 클래스를 만들어 그때그때 사용하는 것을 말한다.

 

따라서 상속관계와 포함관계의 경우를 정확히 구분하는 것이 좋다. 그 때 나오는 것이 is-a 관계와 has-a 관계로, 이전에 헤드퍼스트자바할 때 나왔지만,

is-a 관계는 '~는 ~이다.' 라는 명제가 성립하는 관계로, 상속관계,

has-a 관계는 '~는 ~을 가지고 있다.'라는 명제가 성립하는 포함관계다.


단일 상속

이것도 헤드퍼스트에서 한 건데..

자바에서 한 클래스는 여러 개의 상위클래스를 둘 수 없다.

 

중복상속을 하면 상속의 장점을 극대화하고 다양한 범위에 상속을 적용시킬 수 있으나

클래스 이름이나 인스턴스, 메서드명이 중복되면 그것이 어느 클래스에서 온 것인지 알 수 없기 때문에.. 막상 적용하기는 어렵다. 파이썬은 따로 상속순서를 적용하여 이 문제를 해결하지만 자바는 이를 지원하지 않는다.

그렇다고 상위클래스 간의 중복되는 메서드명을 바꾸자니 한 클래스가 다른 클래스랑 연관되어 있을 경우 줄줄이 수정해야하고 코드도 꼬이고하니까 그냥 중복상속의 이점을 포기하고 단일상속만 허용하게 된다.

 

이러면 좀 불편하긴해도 코드신뢰성도 올라가고, 또 나중에 나오지만 구현체를 사용하거나 has-a 관계를 사용하면 약간 이 문제가 상쇄되기 때문에 그냥 단일상속만을 허용한다.


오버라이딩

상위클래스로부터 상속받은 메서드를 하위클래스에 맞게 변경하는 것을 뜻한다.

오버라이딩의 경우에는 상속받은 메서드와 이름, 매개변수, 반환타입이 모두 같아야한다.

다만 접근제어자는 상위클래스보다 넓은 범위에서 가능하고(상위클래스에서 protected로 선언되었으면 protected나 public만 사용가능)

예외 선언의 경우에는 상위클래스보다 많이 선언할 수 없다. 추가로 상위클래스에서 IOException 등의 예외처리를 했으나 하위클래스에서 Exception을 예외선언으로 처리하면 더 많은 예외 처리가 가능하므로 잘못된 예외선언이다.

 

정적메서드는 오버라이딩이라는 개념이 없고 그냥 '하위클래스에서 정적메서드를 새로 정의했다'에 가깝다. 정적멤버는 상속 대상이 아니다.


super()

super는 하위메서드에서 상위메서드를 호출할 때 쓰이는 참조변수다. 사용례는 다르지만 this와 약간 비슷한 위치에 있다. 물론 상위클래스의 멤버는 하위클래스의 멤버이므로 this를 사용해도된다. 그래서 멤버가 중복정의되어 서로 구별해야할 때 super를 사용해야한다.

 

class Member {
    int age = 28;
}

class Singer extends Member {
    public void method() {
        System.out.println("age in Member : " + super.age);
        System.out.println("age in Singer : " + this.age);
    }
}

class Member {
    int age = 28;
}

class Singer extends Member {
    int age = 33;

    public void method() {
        System.out.println("age in Member : " + super.age);
        System.out.println("age in Singer : " + this.age);
    }
}

이렇게..

하위클래스에서 인스턴스 변수의 값이 변했다면 super와 this를 구분해야하지만, 그렇지 않고 상속받은 값을 그대로 썼다면 this를 쓰나 super를 쓰나 큰 상관이 없다. 상속받은 값을 그대로 쓴다면 this와 super는 동일하다. 

 

class Member {
    int age = 28;

    public void method() {
        System.out.println("It is Member");
    }
}

class Singer extends Member {
    public void method() {
        super.method();
        System.out.println("It is Singer");
    }
}

이는 메서드에도 동일하게 적용된다.


조상 생성하기 - super()

this()가 동일클래스의 다른 생성자를 호출했다면, super()는 상위클래스의 생성자를 호출한다.

 

하위클래스를 호출하면 하위클래스와 연결된 모든 상위클래스들이 합쳐져 하나의 인스턴스로 만들어진다. 위에서 Singer를 호출했다면 Singer - Member - ... - 최종적으로는 Object 클래스까지 호출되어 하나의 인스턴스가 된다.

 

이 때 하위클래스가 상위클래스의 자원을 활용하려면 상위클래스의 초기화가 필요하고, 하위클래스의 생성자에서 상위클래스의 생성자를 호출해야한다. 다만 상위클래스를 호출하는 생성자가 없어도 컴파일러가 자동으로 super();를 생성자 코드의 맨 첫줄에 넣어준다.

 

다만 여기서 알아야할 것은 super() 로 상위클래스의 생성자를 불러왔는데 상위클래스의 생성자가 받는 매개변수와 super()로 넘겨주는 매개변수가 서로 같지 않다면, 호환이 되지 않으면 에러가 터진다.

 

class Member {
    int age;
    String name;

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

class Singer extends Member {
    Singer(int age, String name) {
        super(age, name);
    }
}

즉 이렇게 생성자의 매개변수와 super() 매개변수를 동일하게 맞춘 다음에 넘겨주면 상관이 없지만,

 

class Member {
    int age;
    String name;

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

class Singer extends Member {
    Singer(int age, String name) {
        this.age = age;
        this.name = name;
        super();
    }
}

이런식으로 기본생성자가 없는데 그냥 super()로 생성자를 호출하면 에러가 터진다.

 

이렇게 상위클래스의 멤버는 상위클래스의 생서앚에 의해 초기화하는 것이 이상적이다.

 

class Member {
    Member() {
        super();
        System.out.println("생성자 호출됨 : Member");
    }
}

class Singer extends Member {
    Singer() {
        super();
        System.out.println("생성자 호출됨 : Singer");
    }
}

class SingaSongWriter extends Singer {
    SingaSongWriter() {
        super();
        System.out.println("생성자 호출됨 : SingaSongWriter");
    }
}

class Stack {
    public static void main (String[] args) {
        SingaSongWriter s = new SingaSongWriter();
    }
}

 

이렇게 상속구조에서 super()를 통해 생성자를 호출하게되면, 호출순서는 SingaSongWriter → Singer → Member → Object이며, 생성되는 순서는 그 역순으로 생성된다. 그래야 하위클래스가 상위클래스의 멤버를 제대로 알 수 있기 때문이다.

 

이렇게 자바와 OOP의 꽃 중 하나인 상속에 대해서 알아봤다.

상속의 정의, 상속과 포함, 메서드 오버라이딩하기, 오버라이딩된 멤버가 상위멤버를 불러오는 super, 상속에서 상위클래스의 생성자 호출하기 순으로 알아보았다.

 

이전에 생성자를 할 때도 그랬지만, 상속에서의 생성자 역시 다소 어려운 감이 있었는데 이번 기회에 좀 더 자세히 알아보아서 좋았다. 헤드퍼스트자바를 읽을 때는 그냥 책만 읽고 넘어가는 식이라 다소 내용이 어렵고 난해한 감도 약간 있었는데 직접 코드를 짜보고 실제 자바 API 코드도 들여다보고 하니까 더 이해도 잘 되는 것 같다. 재밌다

'언어공부 > Java | Kotlin' 카테고리의 다른 글

[CS] 자바의 정석 독서 #11 - 다형성  (1) 2025.10.09
[CS] 자바의 정석 독서 #10 - 패키지와 접근제어자  (0) 2025.10.02
[CS] 자바의 정석 독서 #8 - 생성자와 초기화  (0) 2025.10.01
[CS] 자바의 정석 독서 #7 - 메서드 오버로딩  (0) 2025.10.01
[CS] 자바의 정석 독서 #6 - 클래스와 메서드  (0) 2025.09.24
'언어공부/Java | Kotlin' 카테고리의 다른 글
  • [CS] 자바의 정석 독서 #11 - 다형성
  • [CS] 자바의 정석 독서 #10 - 패키지와 접근제어자
  • [CS] 자바의 정석 독서 #8 - 생성자와 초기화
  • [CS] 자바의 정석 독서 #7 - 메서드 오버로딩
Radiata
Radiata
개발을 합니다.
  • Radiata
    DDD
    Radiata
  • 전체
    오늘
    어제
    • 분류 전체보기 (211)
      • 신년사 (3)
        • 2025년 (2)
        • 2026년 (1)
      • CS (59)
        • JVM (12)
        • 백엔드 (20)
        • 언어구현 (1)
        • 객체지향 (1)
        • 논리회로 (5)
        • 컴퓨터구조 (9)
        • 데이터베이스 (1)
        • 컴퓨터 네트워크 (10)
      • 언어공부 (64)
        • Java | Kotlin (48)
        • JavaScript | TypeScript (9)
        • C | C++ (6)
      • 개인 프로젝트 (11)
        • [2025] Happy2SendingMails (3)
        • [2026] 골든리포트! (8)
        • [2026] 순수자바로 개발하기 (0)
        • 기타 이것저것 (0)
      • 팀 프로젝트 (29)
        • [2025][GDG]홍대 맛집 아카이빙 프로젝트 (29)
      • 알고리즘 (13)
        • 백준풀이기록 (11)
      • 놀이터 (0)
      • 에러 수정일지 (2)
      • 고찰 (24)
        • CEOS 23기 회고록 (2)
  • 블로그 메뉴

    • CS
    • 언어공부
    • 개인 프로젝트
    • 팀 프로젝트
    • 알고리즘
    • 고찰
    • 신년사
    • 컬러잇 개발블로그
  • 링크

    • 컬러잇 개발블로그
  • 공지사항

  • 인기 글

  • 태그

    144
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.5
Radiata
[CS] 자바의 정석 독서 #9 - 상속
상단으로

티스토리툴바