웹 개발 기초/자바 문법

상속에서의 클래스 생성

sungw00 2022. 12. 5. 15:14
728x90

자바에서 하위 클래스가 생성될 때는 상위 클래스의 생성자가 먼저 호출된다. 상속 관계에서 클래스의 생성 과정을 살펴보면 하위 클래스에서 상위 클래스의 변수와 메서드의 사용이 가능한 이유와 하위 클래스에서 상위 클래스의 자료형으로 형 변환을 할 수 있는 이유를 이해할 수 있다.

 

상위클래스가 Customer( ) 이고, Customer( )의 하위 클래스가 VIPCustomer( )일 때, 클래스가 생성되는 과정을 살펴보면 다음과 같다.

// Customer 클래스 생성
public class Customer {
    protected int customerID;
    protected String customerName;
    protected String customerGrade;
    int bonusPoint;
    double bonusRatio;
    
    public Customer( ) {
    	customerGrade = "SILVER";
        bonusRatio = 0.01;
        System.out.println("Customer( ) 생성자 호출 ");
    }
    
    public int calcPrice(int price) {
    	bonusPoint += price * bonusRatio;
        return price;
    }
    ...
}
// VIPCustomer 클래스 생성
public class VIPCustomer extends Customer {
    private int agentID;
    double saleRatio;
    
    public VIPCustomer( ) {
    	customerGrade = "VIP";
        bonusRatio = 0.05;
        saleRatio = 0.1;
        System.out.println("VIPCustomer( ) 생성자 호출 ");
    }
    
    public int getAgentID( ) {
    	return agentID;
    }
}

상위 클래스의 변수를 private으로 선언하게 되면 하위 클래스에서는 해당 변수를 사용할 수 없는데, 이는 하위 클래스에서 해당 변수에 접근할 수 없기 때문이다.(그래서 protected로 바꿔주어서 상속받은 클래스 이외에는 접근할 수 없게 한 것)

// CustomerTest2 클래스 생성
public class CustomerTest2 {
    public static void main(String[ ] args) {
        VIPCustomer customerKim = new VIPCustomer( );
        customerKim.setCustomerID(10020);
        customerKim.setCustomerName("김유신");
        customerKim.bonusPoint = 10000;
        System.out.println(customerKim.showCustomerInfo());
    }
}
// 출력 결과
Customer( ) 생성자 호출
VIPCustomer( ) 생성자 호출
김유신 님의 등급은 VIP이며, 보너스 포인트는 10000입니다.

출력 결과를 보면 상위 클래스의 Customer( ) 생성자가 먼저 호출되고 이후에 VIPCustomer( )가 호출되는 것을 볼 수 있다.

이것과 같이 상위 클래스를 상속받은 하위 클래스가 생성될 때는 반드시 상위 클래스의 생성자가 먼저 호출된다. 그리고 상위 클래스 생성자가 호출될 때 상위 클래스의 멤버 변수가 메모리에 생성되는 것이다.

 

부모를 부르는 예약어, super

super 예약어는 하위 클래스에서 상위 클래스로 접근할 때 사용한다. 하위 클래스는 상위 클래스의 주소, 즉 참조 값을 알고 있다.

이 참조 값을 가지고 있는 예약어가 바로 super이다. this가 자기 자신의 참조 값을 가지고 있는 것과 마찬가지인 원리이다.

또한 super는 상위 클래스의 생성자를 호출하는 데도 사용한다.

 

위에서 사용했던 예제 중 하위 클래스의 생성자만 호출했는데 상위 클래스의 생성자가 호출되는 이유는 하위 클래스 생성자에서 super( )를 자동으로 호출하기 때문이다. super( )를 호출하면 상위 클래스의 디폴트 생성자가 호출된다. 

물론 super 예약어로 디폴트 생성자가 아닌 매개변수가 있는 생성자를 호출하는 것도 아래 코드처럼 가능하다.

// Customer 클래스 생성
...
public Customer(int customerID, String customerName) {
    this.customerID = customerID;
    this.customerName = customerName;
    customerGrade = "SILVER";
    bonusRatio = 0.01;
    System.out.println("Customer(int, String) 생성자 호출");
}
...

상속받은 VIPCustomer 클래스도 Customer 클래스와 같이 고객 ID와 고객 이름을 반드시 지정해서 생성해야 오류가 발생하지 않는다.

// VIPCustomer 클래스 생성
...
public VIPCustomer(int customerID, String customerName, int agentID) {
    super(customerID, customerName);
    customerGrade = "VIP";
    bonusRatio = 0.05;
    saleRatio = 0.01;
    System.out.println("VIPCustomer( ) 생성자 호출");
}
...
// CustomerTest2 클래스 생성
public class customerTest2 {
    public static void main(String[] args) {
        Customer customerKim = new VIPCustomer(10020, "김유신", 100);
        customerKim.bonusPoint = 10000;
        System.out.println(customerKim.getCustomerInfo());
    }
}

위와 같이 VIPCustomer 클래스는 VIPCustomer형이면서 동시에 Customer형이기도 하다. 즉 VIPCustomer클래스로 인스턴스를 생성할 때 이 인스턴스의 자료형을 Customer형으로 클래스 형 변환하여 선언할 수 있다. 왜냐하면 VIPCustomer 클래스는 Customer 클래스를 상속받았기 때문이다.(=업캐스팅이라고도 함). 

하지만 반대로 Customer로 인스턴스를 생성할 때 VIPCustomer형으로 선언할 수는 없다. 왜냐하면 상위 클래스인 Customer가 VIPCustomer 클래스의 기능을 다 가지고 있는 것은 아니기 때문이다.

728x90