본문 바로가기
JAVA

[자바/JAVA] 상속(Inheritance)

by wook99 2024. 6. 14.

이번 포스팅은 자바 객체지향프로그래밍의 핵심 개념 중 하나인 상속에 대한 내용이다.

기존 클래스의 필드와 메서드를 새로운 클래스에서 재사용하게 해준다. 상속이라는 단어의 뜻 그대로 기존 클래스의 속성(변수)와 기능(메서드)를 그대로 물려받는 것이다.

 

몇가지 용어 정리를 하고 들어가보자.

  • 부모 클래스(super class) : 상속을 통해 자신의 필드와 메서드를 다른 클래스에 제공하는 클래스
  • 자식 클래스(sub class) : 부모 클래스로부터 필드와 메서드를 상속받는 클래스
  • extends : 상속을 사용하기 위해 사용되는 키워드. 대상 하나만 선택 가능

장점

  • 코드 재사용을 통한 중복 제거를 할 수 있는 장점.
  • 부모 클래스를 통한 기능 확장
  • 유지보수성

1. 사용

코드를 통해 개념을 알아보자.

public class GasCar {

    public void move(){
        System.out.println("차를 이동합니다.");
    }

    public void fillUp(){
        System.out.println("주유를 시작합니다.");
    }
}
public class ElectricCar {

    public void move(){
        System.out.println("차를 이동합니다.");
    }

    public void charge(){
        System.out.println("차를 충전합니다.");
    }
}

 

가스차와 전기차는 연료를 충전하는 방식은 다르지만, 이동한다는 특성은 공통부분이라고 할 수 있다.

그렇다면 수소차, 하이브리드차 등 움직일 수 있는 이동 수단에 대한 move()를 해당 클래스에 모두 작성해야할까?

모두 중복되는 코드이므로 Car라는 클래스에 공통 기능으로 넣어주고, 각 차들이 상속을 받으면 이는 해결된다. 

 

public class Car {

    public void move(){
        System.out.println("차를 이동합니다.");
    }
}
public class ElectricCar extends Car {
    public void charge(){
        System.out.println("차를 충전합니다.");
    }
}
public class GasCar extends Car{

    public void fillUp(){
        System.out.println("기름을 주유합니다.");
    }
}

 

전기차와 가스차 클래스는 extends 키워드를 통해 Car클래스를 상속 받았고, move()라는 메서드를 상속받았다고 볼 수 있다. 아래는 사용 예제이다.

 

public class CarMain {
    public static void main(String[] args) {
        ElectricCar electricCar = new ElectricCar();
        electricCar.move();
        electricCar.charge();

        GasCar gasCar = new GasCar();
        gasCar.move();
        gasCar.fillUp();
    }
}

/*실행 결과
차를 이동합니다.
차를 충전합니다.
차를 이동합니다.
기름을 주유합니다.
*/

 

GasCar클래스와 ElectricCar클래스에 move메서드가 없지만, 사용할 수 있는 것을 확인할 수 있다.

이처럼 클래스를 상속받게 되면, 부모 클래스에 있는 필드와 메서드를 자식이 가져다 쓸 수 있다. 

 

만약, Car를 상속받는 모든 클래스에 공통되는 기능을 추가하려면, Car클래스에만 기능을 추가하면 된다. 

아래의 코드로 확인해보자.

public class Car {

    public void move(){
        System.out.println("차를 이동합니다.");
    }

    public void openDoor(){
        System.out.println("문을 엽니다.");
    }
}

 

문을 여는 기능인 openDoor메서드를 추가하였다.


2. 메서드 오버라이딩(Method Overriding)

메서드 오버라이딩 조건

  • 메서드 이름이 같아야 한다.
  • 메서드 매개변수 타입, 순서, 개수가 같아야 한다.
  • 반환 타입이 같아야 한다.
  • 상위 클래스의 메서드보다 더 좁은 범위의 접근 제어자를 사용할 수 없다.
  • static, final, private키워드가 붙은 메서드는 오버라이딩 할 수 없다.
  • 생성자는 오버라이딩 할 수 없다.

 

부모 클래스의 move메서드를 상속받아서 사용을 할 수 있다. 하지만 자식에서 약간의 변화를 주거나 메서드를 재정의 하고 싶을 수도 있다. 그럴때 사용하는게 메서드 오버라이딩이다. 

 

public class Car {

    public void move(){
        System.out.println("차를 이동합니다.");
    }

    public void openDoor(){
        System.out.println("문을 엽니다.");
    }
}
public class ElectricCar extends Car {

    @Override
    public void move(){
        System.out.println("전기차를 빠르게 이동합니다.");
    }

    public void charge(){
        System.out.println("차를 충전합니다.");
    }
}
public class CarMain {
    public static void main(String[] args) {
        ElectricCar electricCar = new ElectricCar();
        electricCar.move();

        GasCar gasCar = new GasCar();
        gasCar.move();
    }
}

/*실행 결과
전기차를 빠르게 이동합니다.
차를 이동합니다.
*/

 

ElectricCar에서는 Car클래스를 상속받았고, move메서드를 수정하여 재정의 하였다. 

@이 붙은 부분은 애노테이션이라고 하며, 주석과 비슷하다. //는 사람이 읽는 주석이라면 @는 프로그램이 읽는 주석이다.

@Override는 자식클래스가 부모 클래스의 메서드를 오버라이드 하는 것임을 프로그램이 인지하게 되는것이다.

애노테이션을 사용하면 프로그램이 사용자의 실수나 조건을 만족시키지 못했을 때 컴파일 에러를 발생시켜준다는 장점이 있다.

 


3. protected

이전에 포스팅 했던 접근제어자의 종류중 protected는 default와 동일하게 같은 패키지 내에서 접근 가능이라는 점이 있지만, 상속은 허용해준다.


https://wook99.tistory.com/98

 

[자바/JAVA] 접근 제어자(Access Modifier)와 캡슐화(Encapsulation)

자바는 public, private와 같은 접근 제어자를 제공한다. 접근 제어자를 사용하면 해당 클래스 외부에서 특정 필드나 메서드에 접근하는 것을 허용하거나 제한할 수 있다. 핵심은 속성과 기능을 외

wook99.tistory.com

 

코드를 통해 확인하면 이해가 쉽다.

 

 

package extends1.access.parent;


public class Parent {

    public int publicValue;
    protected  int protectedValue;
    int defaultValue;
    private int pritvateValue;

    public void publicMethod(){
        System.out.println("Parent.publicMethod");
    }

    protected void protectedMethod(){
        System.out.println("Parent.protectedMethod");
    }

    void defaultMethod(){
        System.out.println("Parent.defaultMethod");
    }

    private void privateMethod(){
        System.out.println("Parent.privateMethod");
    }

    public void printParent(){
        System.out.println("==Parent 메서드 안==");
        System.out.println("publicValue = " + publicValue);
        System.out.println("protectedValue = " + protectedValue);
        System.out.println("defaultValue = " + defaultValue);
        System.out.println("pritvateValue = " + pritvateValue);

        //부모 메서드 안에서 모두 접근 가능
        defaultMethod();
        privateMethod();
    }
}
package extends1.access.child;

import extends1.access.parent.Parent;

public class Child extends Parent {

    public void call(){
        publicValue = 1;
        protectedValue = 1; //상속 관계 or 같은 패키지
//        defaultValue = 1; //다른 패키지 접근 불가
//        privateValue = 1; // 다른 패키지 접근 불가

        publicMethod();
        protectedMethod();
//        defaultMethod();
//        privateMethod();

        printParent();
    }

 

Child클래스는 Parent클래스를 상속받고, 서로 다른 패키지에 위치한다.

Child클래스에서 default는 같은 패키지에서만 접근이 가능하고, private는 같은 클래스내에서만 접근 가능하기에  defaultValue, privateValue, defaultMethod(), privateMethod()는 사용할 수 없다.

하지만 같은 패키지 내에서만 접근 가능하고, 상속 관계에서는 다른패키지 접근을 허용하는 protected는 사용할 수 있다.

 

다음 포스팅은 상속의 중요 개념중 하나인 super를 다뤄보겠음