상속과 오버라이딩

2025. 2. 23. 19:09Java/객체지향

1. 상속

1-1. 상속이란? 

  • 부모 클래스가 가지는 멤버(필드, 메소드)를 자식 클래스가 물려 받아 자신의 멤버인 것처럼 사용할 수 있도록 만든 기술
  • 멤버 외에도 부모 클래스의 타입 또한 상속이 된다. (다형성의 토대)
  • 단, 생성자와 초기화블럭은 상속되지 않는다. 
  • 자손클래스의 인스턴스 = 조상 클래스의 멤버 + 자손 클래스의 멤버
  • 따라서 자손 클래스의 멤버개수는 조상 클래스보다 항상 같거나 많다
  • 자바는 단일상속(자식 클래스는 하나의 부모 클래스만 가지는)만 지원한다.

자바는 단일 상속만을 지원

 

1-2. 상속의 장점

  • 클래스 간 계층 관계를 형성하여 다형성 문법의 토대가 된다.
  • 코드의 재사용성을 높히고 코드의 중복을 제거하여 프로그램의 생산성과 유지보수에 기여한다.
  • 코드의 추가 및 변경이 용이: 상속을 통해 클래스를 작성하면 보다 적은 양의 코드로 새로운 클래스를 작성할 수 있고 코드를 공통적으로 관리할 수 있기 때문에 코드의 추가 및 변경이 용이하다.

 

1-3. 상속 구현법 : extends 키워드 

public class Cat extends Animal { }
// Animal -> 상속 해주는 클래스: 조상클래스, 부모클래스, 상위 클래스, 기반(base)클래스
// Cat -> 상속 받는 클래스: 자손클래스, 자식클래스, 하위클래스, 파생(derived)클래스

 

 

2. 클래스 간의 관계

  상속 관계 (Is-a) 포함 관계 (Has-a)
의미 클래스 간 상속 관계를 맺는 것 
"자식 클래스는 부모 클래스(의 한 종류)이다.”
한 클래스의 멤버변수로 다른 클래스 타입의 참조변수를 선언하는 것
"부모 클래스는 자식 클래스를 갖고 있다."
관계 부모-자식 클래스-멤버변수
예시 차-소방차
소방차는 차(의 한 종류)이다.
차-바퀴
차는 바퀴를 갖고 있다. 


3. super, super()

3-1. super

  • 자식 클래스의 인스턴스 생성 시 부모 생성자를 호출하여 부모 클래스의 인스턴스도 함께 생성하게 되는데, 이 때 생성한 부모 인스턴스의 주소를 보관하는 레퍼런스 변수
  • 자손클래스에서 조상클래스로부터 상속받은 멤버를 참조하는데 사용된다.
  • 자식 클래스 내의 모든 생성자와 메소드 내에서 묵시적으로 사용할 수 있다.
  • 멤버변수와 지역변수의 이름이 같을 때 this를 써서 구별했듯이, 상속받은 멤버와 자신의 멤버가 이름이 같을 때는 상속받은 멤버에 super을 붙여 구분할 수 있다
  • this와 마찬가지로 super 역시 static메서드에서는 사용할 수 없고 인스턴스 메서드에서만 사용할 수 있다

 

3-2. super()

  • 자식 클래스의 생성자에서 부모 생성자를 호출하는 구문
  • 인자와 매개변수의 타입, 갯수, 순서가 일치하는 부모의 생성자를 호출한다.
  • 부모 클래스의 private 생성자는 호출 불가
  • this()는 같은 클래스의 다른 생성자를 호출하는 데 사용되지만, super()는 조상클래스의 생성자를 호출하는 데 사용된다.
  • 자손 클래스 인스턴스 생성: 조상 클래스 생성자 호출 -> 후손 클래스 생성자 호출
    조상클래스의 멤버의 초기화 작업이 수행되어야 하기 때문에 "자손 클래스의 생성자에서" 조상클래스의 생성자가 호출되어야한다.
  • Object 클래스를 제외한 모든 클래스의 생성자 첫 줄에 super()를 컴파일러가 자동적으로 삽입한다.
public Car(){
    // 모든 생성자에는 맨 첫 줄 위에 super() 를 컴파일러가 자동으로 추가한다.
    // 부모의 기본 생성자를 호출하는 구문으로 명시적, 묵시적으로 사용 가능
    super(); //Object()
    // 모든 클래스는 Object라는 클래스를 최상위 부모로 삼고있었음. (자동)
    // 기본적으로 쓰던 함수들 equals(), clone() 등등 모두 Object의 메서드임
    System.out.println("Car 클래스 기본 생성자 호출");
}

 

 

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

  • Object클래스는 모든 클래스의 상속계층도 최상위에 있는 조상클래스이다.
  • 다른 클래스로부터 상속 받지 않는 모든 클래스들은 자동적으로 Object클래스로부터 상속받게 한다
  • 자바의 모든 클래스들은 Object클래스의 멤버들을 상속 받기 때문에 Object클래스에 정의된 멤버들을 사용할 수 있다. (toString(), equals()등..)

 
4. 오버라이딩 

4-1. 오버라이딩이란?

  • 오버라이딩이란 조상클래스로부터 상속받은 메서드의 내용을 변경하는 것이다.
  • 상속받은 메서드를 그대로 사용하기도 하지만, 자손 클래스 자신에 맞게 변경해야하는 경우 조상의 메서드를 오버라이딩하여 사용한다
  • Spring에서 제공하는 @Override 어노테이션은 오버라이딩 규칙에서 어긋나는 경우 에러를 뱉는다. 

 

4-2. 오버라이딩의 조건

  1. 메소드명, 리턴타입 동일
  2. 매개변수의 타입, 개수, 순서가 동일
  3. 부모 클래스의 private, final 메소드는 오버라이딩 불가능 (protected 가능) 
  4. 접근제어자는 부모 메소드와 같거나 더 넓은 범위여야 함
  5. 예외처리는 같은 예외이거나 더 구체적(하위)인 예외를 처리해야 함
  6.  인스턴스메서드를 static메서드로 또는 그 반대로 변경할 수 없다.
public class SuperClass {
    //오버라이딩 테스트 기준 메소드
    public void method(int num) {}
    private void privateMethod() {}
    public final void finalMethod() {}
    protected void protectedMethod() {}
}

public class SubClass extends SuperClass {
    //오버라이딩 규칙
    //규칙에서 어긋나는 경우 @Override 어노테이션이 에러 뱉음

    //1. 메소드명, 리턴 타입, 매개변수 개수&타입&순서 일치해야 성립
    @Override
    public void method(int num) {}
    //public void method(String num) {}         //매개변수 타입 불일치
    //public void method(int num) { return 0; } //리턴 타입 불일치
    //public void method2(int num) {}           //메소드명 불일치

    //2. private, final 메소드 오버라이딩 불가, protected 가능
    @Override
    //private void privateMethod() {}       //불가능
    //public void finalMethod() {}          //불가능
    //protected void protectedMethod() {}   //가능

    //3. 접근 제어자 범위를 좁히는 것은 불가능
    // public > protect > default > private

    // protect -> default로 변경 불가
    // void protectedMethod() {} //불가

    // protect -> public은 변경 가능
    public void protectedMethod() {} //가능
}

 

 

4-3. 오버로딩 vs. 오버라이딩

  • 오버로딩: 기존에 없는 새로운 메서드를 정의하는 것. 즉 이름은 똑같지만 "매개변수를" 다르게 하는 것.
  • 오버라이딩: 상속받은 메서드의 "내용을" 변경하는것.