본문 바로가기
개발/Java

[3주차] Java 중급 - 상속에서 클래스 생성 과정과 형 변환

by 컴쏘 2023. 6. 24.

하위 클래스가 생성되는 과정

  • 하위 클래스를 생성하면 상위 클래스가 먼저 생성됨
  • new VIPCustomer()를 호출하면 Customer() 가 먼저 호출됨 (상위 클래스가 먼저 호출됨)
  • 클래스가 상속 받은 경우 하위 클래스의 생성자에서는 반드시 상위 클래스의 생성자를 호출

Customer.java

public Customer() { // 생성자 (일반 고객)
		customerGrade = "SILVER";
		bonusRatio = 0.01;
		
		System.out.println("Customer() 생성자 호출"); // 생성자 안에 작성
	}

VIPCustomer.java

public VIPCustomer() {
		customerGrade = "VIP"; // 오류 발생 상속받은 Customer에서 customerGrade가 private이기 때문
		bonusRatio = 0.05;
		salesRatio = 0.1;
		
		System.out.println("VIPCustomer() 생성자 호출"); // 생성자 안에 작성
	}

결과

super 키워드

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

매개변수를 달리할 경우 생성자를 여러개 만들 수 있다. 

하위 클래스에서 상위 클래스의 생성자를 명시적으로 호출해야 할 때는 상위 클래스의 생성자에 맞춰서 호출해줘야한다. (상위 클래스의 생성자가 매개변수가 있으면, 매개변수를 넣어서 호출해주거나...)

 

Customer.java

// 매개변수가 있는 생성자의 경우
public Customer(int customerID, String customerName) {
		this.customerID = customerID; // this는 인스턴스가 자기자신의 주소를 가지고 있을 때, 
		this.customerName = customerName; // class가 생성된 자기자신의 주소를 가지고 있는 값 = this
		// 추가적으로 this는 클래스의 또다른 생성자를 호출할 수 있는 기능이 있다. 		

		customerGrade = "SILVER";
		bonusRatio = 0.01;
		System.out.println("Customer(int, String) 생성자 호출");
	}

VIPCustomer.java

// super를 이용하여 상위 클래스의 생성자 명시적으로 호출
	public VIPCustomer(int customerID, String customerName) {
		super(customerID, customerName); // super는 하위 클래스가 상위 클래스이 참조값을 가지게 된다.
		// super.하면 메소드도 다 볼 수 있고, 호출할 수도 있음(super.안쓰고 그냥 메소드 이름만 써도 가능)
		// super에서도 생성자를 호출할 수 있는 기능이 있음 
		// 만약 super()만 쓰면 default 생성자 호출함 
		// super()를 명시하지 않으면 compiler가 dafault constructor를 넣어준다. 

		customerGrade = "VIP";
		bonusRatio = 0.05;
		salesRatio = 0.1;
		
		System.out.println("VIPCustomer(int, String) 생성자 호출");
	}

CustomerTest.java

package ch03;

public class CustomerTest {
	public static void main(String[] args) {
		//Customer customerLee = new Customer();
		//customerLee.setCustomerName("이순신");
		//customerLee.setCustomerID(10010);
		Customer customerLee = new Customer(10010, "이순신");
		customerLee.bonusPoint = 1000;
		System.out.println(customerLee.showCustomerInfo());
		
		//VIPCustomer customerKim = new VIPCustomer();
		//customerKim.setCustomerName("김유신");
		//customerKim.setCustomerID(10020);
		VIPCustomer customerKim = new VIPCustomer(10020, "김유신");
		customerKim.bonusPoint = 10000;
		System.out.println(customerKim.showCustomerInfo());
	}
}

결과

super()를 사용한 경우

public VIPCustomer(int customerID, String customerName) {
		//super(customerID, customerName);
		super();
		
		customerGrade = "VIP";
		bonusRatio = 0.05;
		salesRatio = 0.1;
		
		System.out.println("VIPCustomer(int, String) 생성자 호출");
	}

결과

상속에서 인스턴스 메모리의 상태

  • 항상 상위 클래스의 인스턴스가 먼저 생성되고, 하위 클래스의 인스턴스가 생성됨 (그림 순서상으로는 1 생성 후 2 생성) 
  • private도 다 만들어진다. 단지 접근만 못하는 것임 

형 변환(업캐스팅)

1. 상위 클래스로 변수를 선언하고 하위 클래스의 생성자로 인스턴스를 생성

// 사용 예시 
Customer customerLee = new VIPCustomer();
// 이렇게 사용할 수 있는 이유는 VIPCustomer가 Customer type을 내포하고 있기 때문

2. 상위 클래스 타입의 변수에 하위 클래스 변수가 대입

VIPCustomer vCustomer = new VIPCustomer(); 
addCustomer(vCustomer);
// addCustomer의 매개변수를 보면 Customer type으로 받아준다. 
// 이렇게 매개변수로 넘겨줘도 받는다. 
// VIPCustomer type이어도 Customer type을 내포하고 있기 때문 
int addCustomer(Customer customer) {
}

하위 클래스는 상위 클래스의 타입을 내포하고 있으므로 상위 클래스의 묵시적 형 변환이 가능

상속 관계에서 모든 하위 클래스는 상위 클래스로 형 변환(업캐스팅)이 됨 (그 역은 성립하지 않음)

형 변환과 메모리

  • Customer vc = new VIPCustomer(); 에서 vc가 가리키는 것은? 그림의 1번 부분 
  • VIPCustomer() 생성자에 의해 VIPCustomer 클래스의 모든 멤버 변수에 대한 메모리는 생성되었지만, 변수의 타입이 Customer이므로 실제 접근 가능한 변수나 메서드는 Customer의 변수와 메서드임

클래스의 계층구조가 여러 단계인 경우

상속 관계가 이렇다고 할 때

Human은 내부적으로 Promate와 mammal의 타입을 모두 내포하고 있음

Primate pHumman = new Humman();
Mammal mHumman = new Humman();

2023 KAKAO Tech Campus_BackEnd 필수 과정
Java 3주차 강의 정리 내용입니다.