Welcome! Everything is fine.

[2-3] 상속과 다형성(1) ~ (2) 본문

자격증 및 기타 활동/J2KB

[2-3] 상속과 다형성(1) ~ (2)

개발곰발 2021. 8. 21.
728x90

💡 상속

상속을 사용하면 객체 지향 프로그램에서 다형성을 구현할 수 있다. 클래스를 정의할 때, 이미 구현된 클래스를 상속받아서 속성이나 기능이 확장되는 클래스를 구현한다. 상속이라는 것이 무조건 어떤 클래스를 가져다 쓴다는 의미는 아니다. 일반적인 클래스가 이미 정의가 되어있고, 그 클래스보다 좀 더 구체적인 클래스를 만들때 사용한다. 상속을 쓸 때는 다음과 같이 extends 키워드와 함께 사용한다.

class B extends A{

}

✔ 상속 하는 클래스 : 상위 클래스, parent class

✔ 상속 받는 클래스 : 하위 클래스, child class

✔ 상위 클래스는 하위 클래스보다 일반적인 의미를 가짐.

 하위 클래스는 상위 클래스보다 구체적인 의미를 가짐.

 

강의에 나온 예시 코드로 설명하자면, Customer에서 구체화하여 SILVER Customer, GOLD Customer, VIP Customer 등으로 고객 등급을 나눌 수 있다. 이때 상속을 활용해서 등급에 따라 다른 서비스를 제공하는 고객맞춤서비스를 만들 수 있다. 아래 코드에서는 고객 클래스를 상속받아 VIP 고객 클래스만 만들어 본 것이다.

public class Customer {
	
	protected int customerID;
	protected String customerName;
	protected String customerGrade;
	int bonusPoint;
	protected double bonusRatio;
	
	public Customer() {
		customerGrade = "SILVER";
		bonusRatio = 0.01;
	}

	public int calcPrice(int price) {
		
		if(customerGrade == "SILVER") {
			bonusPoint += price * bonusRatio;
		}
		return price;
	}
	
	public String showCustomerInfo() {
		return customerName + " 님의 등급은 " + customerGrade + "이며, 
        보너스 포인트는 " + bonusPoint + "입니다.";
	}

	public int getCustomerID() {
		return customerID;
	}

	public void setCustomerID(int customerID) {
		this.customerID = customerID;
	}

	public String getCustomerName() {
		return customerName;
	}

	public void setCustomerName(String customerName) {
		this.customerName = customerName;
	}

	public String getCustomerGrade() {
		return customerGrade;
	}

	public void setCustomerGrade(String customerGrade) {
		this.customerGrade = customerGrade;
	}
	
}

extends 키워드를 이용하여 Customer 클래스를 상속받은 VIP Customer 클래스이다. 이 클래스에서는 agentID와 saleRatio만 변수로 선언했음에도 불구하고 Customer 클래스에 있는 변수를 사용할 수 있다.

public class VIPcustomer extends Customer{
	
	private int agentID;
	private double saleRatio;
	
	public VIPcustomer() {
		
		customerGrade = "VIP";
		bonusRatio = 0.05;
		saleRatio = 0.1;
	}
	public int getAgentID() {
		return agentID;
	}
}
public class CustomerTest1 {

	public static void main(String[] args) {
		Customer customerLee = new Customer();
		customerLee.setCustomerID(10100);
		customerLee.setCustomerName("Lee");
		
		VIPcustomer customerKim = new VIPcustomer();
		customerKim.setCustomerID(10101);
		customerKim.setCustomerName("Kim");
		
		System.out.println(customerLee.showCustomerInfo());
		System.out.println(customerKim.showCustomerInfo());

	}
}

출력 결과는 다음과 같다.

Lee 님의 등급은 SILVER이며, 보너스 포인트는 0입니다.
Kim 님의 등급은 VIP이며, 보너스 포인트는 0입니다.

위 코드에서 주의해야할 점 중 하나는 Customer 클래스에서 private 접근 제한자를 사용하여 변수를 선언했다면 오류가 발생한다는 점이다. private를 사용하면 외부 클래스에서 보이지 않는 상태, 즉 가시성이 없는 상태가 되어 접근할 수 없다. 따라서 protected를 사용하였다. protected 접근 제한자를 사용하면 상속 관계에서는 가시성이 있는 상태가 되고, public처럼 사용할 수 있다. 특히 protected는 각각의 클래스가 다른 패키지에 있더라도 외부 클래스에서 보인다. default(접근 제한자가 선언되지 않은 상태)라면 다른 패키지에서 보이지 않는다. 

 

✔ 접근 제한자 가시성

  외부 클래스 하위 클래스 동일 클래스 내부 클래스
public O O O O
protected X O O O
default X X O O
private X X X O

상속에서 클래스 생성 과정 및 메모리 상태

하위클래스가 생성 될때는 항상 상위 클래스가 먼저 생성된다. 즉 상위 클래스의 인스턴스가 먼저 생성이 되고, 하위클래스의 인스턴스가 생성 된다. 상위 클래스의 생성자가 호출되면서 각 멤버 변수들의 메모리가 힙 메모리에 잡힌다. 만약 private 변수가 있다면, 그 변수가 보이지 않는다고 해서 생성되지 않은 것이 아니라, 생성을 되었지만 보이지 않는 것 뿐이다.

super 예약어

this가 자기 자신의 인스턴스 주소를 가지는 것처럼 super는 하위 클래스가 상위 클래스에 대한 주소를 가지게 된다. 하위 클래스가 상위클래스에 접근할 때 사용할 수 있다.

상위 클래스로의 묵시적 형 변환(업캐스팅)

위의 예시 코드에서 상위 클래스로의 묵시적인 형 변환을 하는 법은 다음과 같다.

Customer vc = new VIPCustomer();

VIPCustomer() 생성자의 호출로 인스턴스는 모두 생성되었지만, 타입이 Customer 이므로 접근할 수 있는 변수나 메서드는  Customer의 변수와 메서드이다.