상속

상속이란?

말 그대로 부모에게 물려받는다는 뜻이다. 상위 클래스의 멤버를 하위 클래스가 모두 사용할 수 있으며 기존의 클래스를 재사용하여 새로운 클래스를 만드는 것을 말한다.

1. 상속의 정의와 장점

1.1. 정의

'extends' 키워드를 이용하여 상속을 받는다. 

class Child extends Parent {}

1.2. 장점

  1. 적은 양의 코드로 새로운 클래스를 생성할 수 있다.
  2. 코드를 공통으로 관리하기 때문에 추가 및 변경이 용이하다.
  3. 코드의 중복을 제거하고 재사용성을 높이고 생산성과 유지보수에 크게 기여한다.

* 용어

Parent : 조상 클래스, 부모 클래스, 상위 클래스, 기반 클래스

Child : 자식 클래스, 하위 클래스, 파생 클래스

2. 상속 관계도 (상속 계층도)

 

class Child extends Parent {}
  • Child 클래스는 Parent 클래스의 멤버 들을 모두 포함하고 있다.
  • Parent 클래스에 age라는 변수를 추가 하면 Child 클래스도 자동으로 age라는 변수를 추가하는 것과 같은 효과가 있다.
  • 위와 반대로 Child 클래스에 play() 메서드를 추가하면 Parent 클래스에는 영향이 없다.
  • Parent 클래스를 확장한다고 표현한다.
  • 생성자와 초기화 블럭은 상속되지 않고 멤버(변수, 클래스)만 상속된다.
  • Child 클래스는 Parent 클래스보다 멤버의 개수가 같거나 많다.

* 중요

접근 제어자가 private 또는 default인 멤버는 상속이 되지만 Child 클래스에서 접근이 제한된다.

3. 클래스 간의 관계 - 포함 관계

멤버 변수로 다른 클래스 인스턴스를 생성하여 포함관계를 맺는다.

class Circle {
    Point p = new Point(); // 포함
    int r;
}

class Point {
    int x;
    int y;
}

4. 클래스 간의 관계 결정하기

상속 관계 : ~은 ~이다. (is ~ a)

포함 관계 : ~은 ~을 가지고 있다. (has ~ a)

// 상속 관계
class SportsCar extends Car {}

// 포함 관계
class Circle {
    Point p = new Point();
}
  • 가능한 많은 관계를 맺어주어 코드의 재사용성을 높여야 한다.
  • Child, Parent의 이름이 같은 메서드는 Child 메서드가 실행되며, 이것을 '오버라이딩'이라고 한다.
  • 참조 변수를 출력하면 참조 변수가 가리키고 있는 인스턴스의 toString을 호출하여 출력한다.
    모든 클래스의 최상위인 Object클래스에 정의된 toString()을 호출하는 것이 가능하다.
    ex) Card c = new Card();
    System.out.println(c); === System.out.println(c.toString); 두 개의 예제는 동일하다.

5. 단일 상속 (single inheritance)

단일 상속은 하위 클래스가 상위 클래스를 한 개만 상속받을 수 있다는 뜻이다.

여러 개의 클래스로부터 상속받을 수 없으며 여러 상위 클래스의 멤버 이름이 겹치면 구분 방법이 없기 때문이다.

해결 방안으로는 TV 클래스를 상속받고 VCR 클래스를 포함시킬 수 있다.

// 상속과 포함
class TVCR extends TV {
    VCR vcr = new VCR();
}

// 여러 상위 클래스 상속 불가
class TVCR extends TV, VCR {
    ...
}

6. Object 클래스 - 모든 클래스의 조상

다른 클래스로부터 상속받지 않는 클래스들은 모두 자동으로 Object 클래스를 상속받는다. 컴파일러가 추가해준다.

상속 클래스가 있더라도 상위로 계속 올라가면 최상위에는 Object 클래스를 상속받는다.

상속 계층도에서도 Object가 생략되는 경우가 많다.

7. 오버라이딩 (Overriding)

오버라이딩이란?

상속받은 메서드의 내용을 변경하는 것이 오버라이딩이다.

class Parent {
    public int get() {}
}

class Child extends Parent {
    public int get() {} // 오버라이딩
}

Parent 클래스의 get메서드와 비슷한 기능을 기대할 수 있어 오버라이딩을 사용한다.

7.1. 오버라이딩의 조건

  1. 하위 클래스와 상위 클래스의 메서드 명이 같아야 한다.
  2. 하위 클래스와 상위 클래스의 메서드 매개변수가 같아야 한다.
  3. 하위 클래스와 상위 클래스의 메서드 반환 타입이 같아야 한다.

7.2. 제한된 조건하에 변경 가능한 것

  1. 접근 제어자는 상위 클래스의 메서드 보다 좁은 범위로 변경 불가능하지만 넓은 범위로 변경 가능하다.
    범위 순서 : public > protected > default > private
  2. 상위 클래스의 메서드 보다 많은 예외를 선언할 수 없다.
    상위 메서드 : public int get() throws IOException, SQL.... {}
    하위 메서드 : public int get() throws IOException {}

7.3. 오버라이딩의 제한

  1. 접근 제어자를 상위 클래스의 메서드 보다 좁은 범위로 변경 불가능하다.
  2. 예외는 상위 클래스의 메서드 보다 많이 선언 불가능하다.
  3. 인스턴스 메서드를 static 메서드로, static 메서드를 인스턴스 메서드로 변경 불가능하다.

* 중요

상위 클래스에 정의된 static 메서드를 하위 클래스에 똑같은 선어부로 정의 가능하다. 이것은 오버라이딩이 아닌 각 클래스의 static 메서드이다.

8. Super

  • 상위 클래스의 멤버를 참조하는 참조 변수이다.
  • 인스턴스 메서드에서만 사용 가능하다.
  • 상위, 하위 클래스의 멤버가 같아 혼동이 올 때 사용하는 것이 좋다.
  • 상위 클래스의 멤버도 this를 이용해 사용할 수 있다.
  • 오버라이딩 된 메서드에서 상위 메서드 호출시 사용한다.
  • 오버라이딩 된 메서드에서 상위 메서드를 포함시키는 것이 좋다.
    - 추후 업데이트가 돼도 동작하기 때문
    - 상위 메서드에서 추가 작업이 필요할 경우
class Parent {
    public String name;
    
    public int get() {}
}

class Child {
    Child() {
        super(); // 상위 클래스 생성자 호출
        super.name; // 상위 클래스 멤버 변수
        super.get(); // 상위 클래스 메서드 호출
        
    }
    public int get() {]
}

9. Super() - 상위 클래스의 생성자

  • this()와 마찬가지로 생성자이다.
  • 상위 클래스의 멤버 변수도 초기화가 필요하여 사용한다.
  • Object 클래스를 제외하고는 모두 생성자를 첫 줄에 정의한다.
  • 생성자 첫줄에 상위 클래스의 생성자인 super나 자기 자신의 생성자 this가 없으면 컴파일러가 자동으로 추가한다.
  • 상위 클래스의 멤버 변수는 상위 클래스의 생성자를 통해 초기화가 필요하다.
class Parent {
    public String name;
    
    Parent(String name) {
        this.name = name;
    }
    
    public int get() {}
}

class Child {
    Child() {
        super("홍길동"); // 상위 클래스 생성자 호출        
    }
    
    public int get() {]
}

'개발 언어 > Java' 카테고리의 다른 글

[Java] 제어자  (0) 2021.08.25
[Java] Package와 import  (0) 2021.08.24
[Java] 변수의 초기화  (0) 2021.08.24
[Java] 생성자  (0) 2021.08.24
[Java] 오버로딩과 오버라이딩  (0) 2021.08.24

+ Recent posts