본문 바로가기
JAVA/객체지향

자바 객체 간의 상속(extend) 의미, 구현방법

by 스코리아 2023. 8. 25.

안녕하세요, 스코리아입니다.

오늘은 자바 객체 간의 상속의 의미와 구현 방법을 예시와 함께 알아보겠습니다.

 

클래스 상속 (Class Inheritance) 의미

  • 새로운 클래스를 정의할 때 이미 구현된 클래스를 상속받아서 속성이나 기능을 확장하여 클래스를 구현함
  • 이미 구현된 클래스보다 더 구체적인 기능을 가진 클래스를 구현해야 할 때 기존 클래스를 상속

클래스 상속

  • 상속하는 클래스: 상위 클래스, parent class, base class, super class
  • 상속받는 클래스: 하위 클래스, child class, derived class, sub class

 

상속 문법 (방법)

class B extends A {
}

 

상속을 구현하는 경우

  • 상위 클래스는 하위 클래스보다 더 일반적인 개념, 기능을 가짐
  • 하위 클래스는 상위 클래스보다 더 구체적인 개념, 기능을 가짐
  • 하위 클래스가 상위 클래스의 속성, 기능을 확장(extends)한다는 의미

상속 구현 예시

class Mammal{
}

class Human extends Mammal{
}
  • 예시처럼 포유류 안에 사람이 있으므로 사람은 하위 클래스, 포유류는 상위 클래스라고 할 수 있음
  • 사람(하위 클래스)이 더 구체적인 개념을 갖고 포유류(상위 클래스)가 더 일반적인 개념을 가짐
  • 사람(하위 클래스)가 포유류(상위 클래스)의 속성, 기능을 더 확장함

 

상속을 활용한 예시

  • 회사에서 일반고객(Customer)우수고객(VIPCustomer)에 따른 서비스를 제공하고자 함
  • 등급에 따라 고객이 물품을 구매할 때 적용되는 할인률과 적립되는 보너스 포인트의 비율이 다름
  • 물품 구매 시일반고객은 1% 보너스 포인트 적립, 우수고객은 5% 보너스 포인트 적립
  • 물품 구매 시 일반고객은 할인 없음, 우수고객은 10% 할인
  • 일반 고객은 Silver 등급을, 우수고객은 VIP 등급을 부여
  • 이런 멤버십에 대한 구현을 클래스 상속을 활용해 구현해 보기

우선 일반고객 클래스를 구현하기 위해 Customer.java 파일을 만들어보겠습니다.

public class Customer {
    protected int customerID;
    protected String customerName; // protected : 외부 클래스는 접근 할 수 없지만, 같은 패키지내 하위 클래스는 접근 할 수 있도록함
    protected String customerGrade; // 등급
    protected int bonusPoint; // 보너스 포인트
    protected double bonusRatio; // 보너스 적립 비율

	// 기본 생성자가 아닌 매개 변수가 있는 생성자
    public Customer(int customerID, String customerName, int bonusPoint) {
        System.out.println("Customer() 생성자 호출");
        this.customerID = customerID;
        this.customerName = customerName;
        this.bonusPoint = bonusPoint;
        customerGrade = "SILVER";
        bonusRatio = 0.01;
    }

    public String showCustomerInfo() {
        return customerName + "님의 등급은 " + customerGrade + "이며, 보너스 포인트는" + bonusPoint + "입니다";
    }
}
  • 멤버 변수로 고객 아이디(customerId), 고객 이름(customerName), 고객 등급(customerGrade), 보너스 포인트(bonusPoint), 보너스 포인트 적립 비율(bonusRatio)을 만들어 주었습니다.
  • 고객 아이디, 이름, 보너스 포인트를 매개 변수로 받는 Customer() 생성자를 만들고, 1%의 보너스 포인트 적립을 위해 bonusRatio를 0.01로 설정, customerGrade는 SILVER로 설정하였습니다.
  • 고객의 정보를 출력하는 showCustomerInfo() 메소드를 만들어 주었습니다.

  • 여기서 멤버 변수들을 모두 protected 접근 제어자로 설정함으로써, 외부 클래스는 접근 불가능하지만 같은 클래스 내 하위 클래스는 접근 가능하게끔 하였습니다. 
  • 상위 클래스(Customer.class) 멤버변수에 private 접근 제어자를 사용하게 되면, 하위 클래스에서는 접근이 불가하고 같은 클래스 내에서만 접근이 가능합니다.

이제 하위 클래스인 우수 고객 클래스를 구현하기 위해 VIPCustomer.java 파일을 만들어보겠습니다.

// VIPCustomer는 이미 Customer에 구현된 내용과 중복되므로 Customer를 확장하여 구현함 (상속)
public class VIPCustomer extends Customer{
    private int agentId;
    private double salesRatio;

    public VIPCustomer(int customerID, String customerName, int bonusPoint) {
        super(customerID, customerName, bonusPoint); // super를 이용하여 상위 클래스의 생성자 명시적 호출
        System.out.println("VIPCustomer() 생성자 호출");
        customerGrade = "VIP";
        bonusRatio = 0.05;
        salesRatio = 0.1;
    }
}
  • Customer에 구현된 내용을 VIPCustomer도 똑같이 사용할 필요가 있습니다.
  • 즉, VIPCustomer는 이미 Customer에 구현된 내용이 중복되므로 Customer를 확장(extends)하여 구현합니다.
  • 'extends' 키워드를 사용하여 Customer를 상속받을 것을 암시했습니다.
  • 멤버 변수로 담당 전문 상담원(agentId)과 할인률(salesRatio)을 만들어주었습니다.

클래스 상속 예시

  • 위 그림과 같이 상속 관계를 표현할 수 있습니다.
  • 나중에 VIP Customer뿐만 아니라 Gold Customer, Platinum Customer 등을 추가할 수 있습니다.

super 키워드

  • 하위 클래스에서 가지는 상위 클래스에 대한 참조 값
  • super()는 상위 클래스의 기본 생성자를 호출
  • 상위 클래스의 기본 생성자가 존재하는 경우: 하위 클래스 생성자에서 명시적으로 super() 호출을 하지 않으면, 자동으로 super()가 호출됨
  • 상위 클래스의 기본 생성자가 존재하지 않는 경우 (다른 생성자 존재): 하위 클래스 생성자에서 super() 호출을 통해 명시적으로 상위 클래스의 생성자를 호출해야 함
  • super는 생성된 상위 클래스의 인스턴스 참조 값을 가지므로 super를 이용하여 상위 클래스의 메소드나 멤버변수에 접근할 수 있음 (위의 예시를 보면, bonusRatio가 아닌 super.bonusRatio라고 적을 수 있음)

  • 상위 클래스인 Customer에서 customerGrade를 private로 설정했다면 하위 클래스인 VIPCustomer의 생성자에서는 customerGrade 변수 접근이 불가능했을 것입니다. 그러므로 protected 접근자로 설정해 준 것입니다.

이제 Customer, VIPCustomer 인스턴스를 만들어 테스트해 보기 위해 CustomerTest.java 파일을 만들어보겠습니다.

public class CustomerTest {
    public static void main(String[] args) {
        Customer customerLee = new Customer(10010, "손흥민", 1000);
        System.out.println(customerLee.showCustomerInfo());

        VIPCustomer customerKim = new VIPCustomer(10020, "김민재", 10000);
        System.out.println(customerKim.showCustomerInfo());
    }
}
  • "손흥민" 이름을 가진 Customer 인스턴스를 생성 후, showCustomerInfo 메소드를 호출하였습니다.
  • "김민재" 이름을 가진 VIPCustomer 인스턴스를 생성 후, showCustomerInfo 메소드를 호출하였습니다.
  • VIPCustomer 파일 자체에는 showCustomerInfo 메소드가 없지만, VIPCustomer는 Customer를 상속받고 있기 때문에 상위 클래스 메소드 호출이 가능합니다.

객체간의 상속 테스트 - 출력 결과

  1. Customer 생성자가 처음에 호출되었습니다.
  2. Customer의 showCustomerInfo 메소드가 호출되어 "손흥민" 고객님의 정보가 출력되었습니다.
  3. VIPCustomer 생성자를 호출하면, super() 키워드 때문에 상위 클래스인 Customer 클래스의 생성자가 먼저 호출되었습니다.
  4. 그 후, VIPCustomer 생성자가 호출되었습니다.
  5. VIPCustomer(Customer)의 showCustomerInfo 메소드가 호출되어 "김민재" 고객님의 정보가 출력되었습니다.

  • Customer, VIPCustomer에 매개 변수가 있는 생성자가 아닌 기본 생성자만 존재하고, VIPCustomer 생성자에 super 키워드를 생략한다면, 하위 클래스를 생성하면 이때도 마찬가지로 상위 클래스가 먼저 생성됩니다.
  • 즉, 이 상황에서 new VIPCustomer()를 호출하면 Customer()가 먼저 호출됩니다.
  • 클래스가 상속받은 경우 하위 클래스의 생성자는 반드시 상위 클래스의 생성자를 우선적으로 호출합니다.

 


지금까지 자바(Java)의 객체 간의 상속 의미, 구현방법, 예시에 대해서 알아보았습니다.

읽어주셔서, 감사합니다.