하위 클래스가 생성될 때는 상위 클래스의 생성자가 먼저 호출된다.
하위 클래스가 생성되는 과정
상속된 하위 클래스가 생성되는 과정을 다시 살펴보기 위해 Customer와 VIPCustomer 클래스에 생성자 출력문 추가하여 출력 결과를 확인해본다.
[실습] 상속에서 클래스 생성 과정 (1)
package inheritance;
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;
}
...
}
[실습] 상속에서 클래스 생성 과정 (2)
package inheritance;
public class VIPCustomer extends Customer {
private int agentID; // VIP 고객 상담원 아이디
double saleRatio; // 할인율
public VIPCustomer() {
customerGrade = "VIP"; // 상위 클래스에서 private 변수이므로 오류 발생
bonusRatio = 0.05;
saleRatio = 0.1;
System.out.println("VIPCustomer() 생성자 호출"); // 하위 클래스 생성할 때 콘솔 출력문
}
public int getAgentID() {
return agentID;
}
}
[실습] 하위 클래스 생성하기
package inheritance;
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()가 호출되는 것을 알 수 있다.
즉, 상위 클래스를 상속받은 하위 클래스가 생성될 때는 반드시 상위 클래스의 생성자가 먼저 호출된다.
그리고 상위 클래스의 생성자가 호출될 때 상위 클래스의 멤버 변수가 메모리에 생성되는 것이다.
위처럼 상위 클래스의 변수가 메모리에 먼저 생성되기 때문에 하위 클래스에서도 이 값을 모두 사용할 수 있다.
그렇다면 private로 선언한 경우 하위 클래스에서 해당 변수를 사용할 수 없었던 것은 private 변수가 생성되지만, 단지 하위 클래스에서 접근할 수 없었기 때문이다.
부모를 부르는 예약어, super
super 예약어는 하위 클래스에서 상위 클래스로 접근할 때 사용한다.
하위 클래스는 상위 클래스의 주소, 즉 참조 값을 알고 있는데, 이 값을 가지고 있는 예약어가 바로 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) 생성자 호출"); //상위 클래스 생성할 때 콘솔 출력문
}
...
이렇게 Customer 클래스의 디폴트 생성자를 없애고 새로운 생성자를 작성하면 Customer 클래스를 상속받은 VIPCustomer 클래스에서 오류가 발생한다.
이 오류는 묵시적으로 호출될 디폴트 생성자 Customer()가 정의되지 않았기 때문에 반드시 명시적으로 다른 생성자를 호출해야 한다는 뜻이다.
[실습] 명시적으로 상위 클래스 생성자 호출하기
...
public VIPCustomer(int customerID, String CustomerName, int agentID) {
super(customerID, customerName);
customerGrade = "VIP"; // 상위 클래스에서 private 변수이므로 오류 발생
bonusRatio = 0.05;
saleRatio = 0.1;
this.agentID = agentID;
System.out.println("VIPCustomer(int, String, int) 생성자 호출"); // 하위 클래스 생성할 때 콘솔 출력문
}
...
이대로 테스트해보면
package inheritance;
public class CustomerTest2 {
public static void main(String[] args) {
VIPCustomer customerKim = new VIPCustomer(10020, "김유신", 1111); // 하위 클래스 생성
// customerKim.setCustomerID(10020);
// customerKim.setCustomerName("김유신");
customerKim.bonusPoint = 10000;
System.out.println(customerKim.showCustomerInfo());
}
}
위처럼 set() 메서드는 주석처리하고 실행해보면
이상 없이 출력되는 것을 확인할 수 있다.
상위 클래스에서 선언한 멤버 변수나 메서드를 하위 클래스에서 참조할 때도 super를 사용한다.
VIPCustomer의 showVIPInfo() 메서드에서 상위 클래스의 showCustomerInfo() 메서드를 참조해 담당 상담원 아이디를 추가로 출력하려고 할 때 아래와 같이 구현이 가능하다.
public String showVIPInfo() {
return super.showCustomerInfo() + "담당 상담원 아이디는 " + agentID + "입니다.";
}
상위 클래스로 묵시적 클래스 형 변환
Customer 클래스보다 VIPCustomer 클래스가 상위 클래스 기능과 더불어 더 많은 기능을 구현하기 때문에 기능이 더 많다.
VIPCustomer는 VIPCustomer 형이기도 하면서 동시에 Customer형이기도 하다.
즉, VIPCustomer 클래스로 인스턴스를 생성할 때 이 인스턴스의 자료형을 Customer형으로 클래스 형 변환하여 선언이 가능한데, 이는 VIPCustomer 클래스가 Customer 클래스를 상속받았기 때문이다.
Customer vc = new VIPCustomer();
'Language > Java' 카테고리의 다른 글
[Java] 다형성(polymorphism) (0) | 2022.12.15 |
---|---|
[Java] 메서드 오버라이딩 (1) | 2022.12.13 |
[Java] 상속이란? (0) | 2022.11.17 |
[Java] ArrayList 클래스 사용하기 (0) | 2022.11.15 |
[Java] 다차원 배열 (0) | 2022.11.12 |