[객체지향] 클래스 상속
2024. 6. 24. 09:46
✅ 상속(Inheritance)
- 클래스 상속
- 새로운 클래스를 정의할 때 이미 구현된 클래스를 상속 받아서 속성이나 기능을 확장하여 클래스를 구현함
- IS-A 관계를 갖는다
- 이미 구현된 클래스보다 ‘더 구체적인 기능’을 가진 클래스를 구현해야 할 때 기존 클래스를 상속한다
- 상속의 목적 중 하나는 코드의 재사용이지만 단순히 코드의 재사용만을 위한 상속을 사용하지 않는다
- 상속의 특징
- 상위 클래스는 하위 클래스보다 더 일반적인 개념과 기능을 가짐
- 하위 클래스는 상위 클래스보다 더 구체적인 개념과 기능을 가짐
- 상속은 하위 클래스가 상위 클래스의 속성과 기능을 확장 extends 한다는 의미를 갖는다
→ 하위 클래스는 상위 클래스의 멤버 변수와 메서드에 추가된 멤버 변수(필드)와 기능(메서드)을 갖는다 - Class B extends A : ’B클래스가 A클래스를 상속받는다’ 는의미
- extends 키워드 뒤에 올 수 있는 클래스(상위 클래스)는 단 하나만 올 수 있음
→ 자바는 클래스간 상속시 단일 상속만 지원
→ 다중 상속시 Diamond Problem으로 모호성이 발생 할 수 있기 때문에(글 하단 참고)
- 상속 예시코드
//상위 클래스
public class Customer {
private int customId;
private String customerName;
protected String customerGrade;
int bonusPoint;
double bonusRatio;
public Customer(){
customerGrade = "SILVER";
bonusRatio = 0.01;
}
public int calcPrice(int price){
bonusPoint += price * bonusRatio;
return price;
}
public String showCustomerInfo(){
return customerName + "님의 등급은 " + customerGrade + "이며, 보너스 포인트는 " + bonusPoint + "입니다";
}
public int getCustomId() {
return customId;
}
public void setCustomId(int customId) {
this.customId = customId;
}
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;
}
}
//하위클래스
public class VIPCustomer extends Customer {
double saleRatio;
private String agentID;
public VIPCustomer(){
bonusRatio = 0.05;
saleRatio = 0.1;
customerGrade = "VIP";
}
public String getAgentID() {
return agentID;
}
}
//실행클래스
package ch02;
public class CustomerTest {
public static void main(String[] args) {
Customer customerLee = new Customer();
customerLee.setCustomerName("이순신");
customerLee.setCustomId(10010);
customerLee.bonusPoint = 1000;
System.out.println(customerLee.showCustomerInfo());
VIPCustomer customerKim = new VIPCustomer();
customerKim.setCustomerName("김유신");
customerKim.setCustomId(10020);
customerKim.bonusPoint = 10000;
System.out.println(customerKim.showCustomerInfo());
}
}
- 하위 클래스가 생성되는 과정
- 하위 클래스를 생성하면 상위 클래스가 먼저 생성된다
- 클래스가 상속받은 경우 하위 클래스 생성자에서는 반드시 상위 클래스의 생성자를 호출한다
- 상위 클래스의 호출은 super 키워드를 통해 호출
- super 키워드
- 하위 클래스에서 가지는 상위 클래스에 대한 참조
- super() 는 상위 클래스의 기본 생성자를 호출한다
- 하위 클래스에서 명시적으로 상위 클래스를 호출하지 않으면 super()가 호출된다 → 이때 반드시 상위 클래스의 기본 생성자가 존재해야 하거나 혹은 생성자 코드가 존재하지 않아야 한다
- 상위 클래스의 기본 생성자가 없고 다른 생성자가 있는 경우 하위 클래스 생성자에서는 super 키워드를
이용하여 반드시 명시적으로 상위 클래스의 생성자를 호출해야 한다 - super 키워드는 생성된 상위 클래스 인스턴스 참조 값을 가지므로 super를 이용하여 상위 클래스의 메서드나 멤버 변수에 접근할 수 있다
- super 키워드 예시코드
//상위클래스
public class Customer {
protected int customId;
protected String customerName;
protected String customerGrade;
int bonusPoint;
double bonusRatio;
public Customer(int customId, String customerName){
this.customId = customId;
this.customerName = customerName;
customerGrade = "SILVER";
bonusRatio = 0.01;
}
public int calcPrice(int price){
bonusPoint += price * bonusRatio;
return price;
}
public String showCustomerInfo(){
return customerName + "님의 등급은 " + customerGrade + "이며, 보너스 포인트는 " + bonusPoint + "입니다";
}
public int getCustomId() {
return customId;
}
public void setCustomId(int customId) {
this.customId = customId;
}
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;
}
}
//하위클래스
public class VIPCustomer extends Customer {
double saleRatio;
private String agentID;
public VIPCustomer(int customerId, String customerName){
super(customerId, customerName);
customerGrade ="VIP";
bonusRatio = 0.05;
saleRatio = 0.1;
}
public String getAgentID() {
return agentID;
}
@Override
public int calcPrice(int price) {
bonusPoint += (price*bonusRatio);
price -= (int)(price*saleRatio);
return super.calcPrice(price);
}
}
//실행 클래스
public class CustomerTest {
public static void main(String[] args) {
Customer customerLee = new Customer(10010, "이순신");
customerLee.bonusPoint = 1000;
int price = customerLee.calcPrice(1000);
System.out.println(customerLee.showCustomerInfo() + price);
VIPCustomer customerKim = new VIPCustomer(10020, "김유신");
customerKim.bonusPoint = 10000;
price = customerKim.calcPrice(1000);
System.out.println(customerKim.showCustomerInfo() + price);
Customer vc = new VIPCustomer(12345, "noname");
int result = vc.calcPrice(1000);
System.out.println(result); // VIPCustomer의 calcPrice() 오버라이드 매서드가 호출
}
}
- 상속에서 인스턴스 메모리 상태
- 항상 상위 클래스의 인스턴스가 먼저 생성된 후 하위 클래스 인스턴스가 생성된다
✅ Diamond Problem 이란? (참고)
✅ 다이아몬드 문제란?
해당 그림과 같이 다중 상속을 허용하게 GrandFather의 메서드를 구현한 FatherA와 FatherB를 상속받는 Son에서 해당 메서드를 호출할 때 어떤 메서드를 호출해야하는지 충돌하는 문제가 생긴다.
예로들면 GrandFather의 callI()이란 메서드를 FatherA와 FatherB가 구현하고 Son에서 call 메서드를 호출 할 때 어떤 메서드를 호출해야하는지 모호성이 발생하는데 이를 Diamond Problem이라고 한다.
따라서 클래스의 상속은 다중상속을 지원하지 않는다
'JAVA > 객체지향' 카테고리의 다른 글
[객체지향] 인터페이스 (0) | 2024.07.08 |
---|---|
[객체지향] 다형성 (0) | 2024.06.26 |
[객체지향] Static (0) | 2024.06.26 |
[객체지향] 업캐스팅 다운캐스팅 (0) | 2024.06.25 |
[객체지향] this (1) | 2024.06.25 |