💡 객체지향 프로그래밍의 특징 중 하나가 상속이다.
- 상속이란, 말 그대로 자식클래스가 부모클래스로부터 멤버변수와 메서드를 사용할 수 있도록 한다.
class 하위클래스(자식클래스) extends 상위클래스(부모클래스) {
}
- 위 코드를 "자식클래스가 부모클래스를 상속받다" 라고 말한다.
- 자바에서 상속을 구현할 때에는 "extends" 예약어를 사용한다.
📌상위클래스(부모클래스)
class Mammal { // 포유류
}
📌하위클래스(자식클래스)
class Human extends Mammal{ // 사람
}
package test;
public class Customer {
protected int customerID; // 고객아이디
protected String customerName; // 고객이름
protected String customerGrade; // 고객등급
int bonusPoint; // 보너스 포인트
double bonusRatio; // 적립비율
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;
}
// 디폴트 생성자
public Customer() {
customerGrade = "SILVER"; // 객체 생성시 고객등급은 실버로 기본설정
bonusRatio = 0.01; // 보너스 포인트 기본적립 비율
}
// 지불가격 계산, 보너스포인트 적립 메서드
public int calcPrice(int price) {
bonusPoint += price * bonusRatio; // 보너스포인트 적립
return price; // 지불가격 리턴
}
// 회원정보를 리턴하는 메서드
public String showCustomerInfo() {
return customerName + " 님의 등급은 " + customerGrade + " 이고, 보너스 포인트는 " + bonusPoint + " 입니다.";
}
}///////////////class
💡 위 코드처럼 구현을 한 상태에서 단골고객이 생겨 새로운 등급에 대한 혜택을 주고싶을 경우
💡 vip고객들을 위한 변수와 메서드를 기존 customer클래스에 추가하는 것이 아닌,
새로운 vipCustomer클래스를 만들어서 따로 관리 해보자
💡 멤버변수에서 private가 아닌 protected를 사용한 이유는 뭘까?
private은 해당 클래스 내에서만 변경이 가능하기 때문에 상속받을 vipCustomer클래스에서는 사용이 불가능하다
하위클래스에서 상위클래스 멤버변수를 사용하되, private과 동일한 기능을 하는 접근제어자를 사용하고자 한다면 protected을 사용하면 된다.
protected은 다른클래스에서 접근은 불가하지만 상속받은 클래스에서는 사용이 가능하다.
💡 각 멤버변수 별로 get, set 메서드를 만든이유는 뭘까?
모든곳에서 수정이되는 public제어자가 아니기 때문에 다른 클래스에서 사용하고자 할 때에는 직접적으로 멤버변수에 관여할 수 없어 get,set메서드를 만들어 초기화할 수 있다.
package test;
public class vipCustomer {
// 멤버변수[기존 Customer클래스와 겹치는 변수가 있다.]
private int customerId; // 고객아이디
private String customerName; // 고객이름
private String customerGrade; // 고객등급
int bonusPoint; // 보너스 포인트
double bonusRatio; // 적립비율
// vip고객 관련기능을 구현할때만 사용 할 멤버변수
private int agentId; // vid고객 담당 상담원 아이디
double saleRatio; // 할인율
// 디폴트 생성자
public vipCustomer() {
customerGrade = "Gold"; // vip고객 경우 객체 생성시 골드가 기본등급
bonusRatio = 0.05; // vip고객 경우 기본 적립금 5%
saleRatio = 0.1; // vip고객 경우 할인율은 10%
}
// 할인가격 계산, 보너스포인트 적립 메서드
public int calcPrice(int price) {
bonusPoint += price * bonusRatio;
return price - (int)(price * saleRatio);
}
// vip고객들을 위한 담당직원아이디
public int getAgentId() {
return agentId;
}
// vip고객들을 위한 담당직원아이디
public void setAgentId(int agentId) {
this.agentId = agentId;
}
public String showCustomerInfo() {
return customerName + "의 등급은 " + customerGrade + "이며, 보너스 포인트는 " + bonusPoint + "입니다.";
}
}///////////////////////class
위 코드처럼 기존Customer클래스 따로, vipCustomer클래스 따로 구현하니 겹치는 부분이 발생하게 된다.
이럴 경우, 상속을 사용하여 클래스를 구현해보자
<package test;
public class vipCustomer extends Customer {
private int agentId; // vip고객 상담원 아이디
double saleRatio; // 할인율
// 디폴트 생성자
public vipCustomer() {
customerGrade = "Gold";
saleRatio = 0.1;
bonusRatio = 0.05;
}
public void setAgentId(int agentId) {
this.agentId = agentId;
}
public int getAgentId() {
return agentId;
}
}///////////////////////class
위와 같이 상속예약어(extends)를 통하여 구현하니 2-2 처럼 겹치는부분없이 코드가 간결해졌다.
이제 두 클래스를 가지고 아래에서 테스트를 해보자
💡문제
📍 일반고객
→ 이름: 이순신
→ 아이디: 10010
→ 보너스 포인트: 1000점
📍 vip고객
→ 이름: 김유신
→ 아이디: 10020
→ 보너스 포인트: 10000점
package test;
public class CustomerTest {
public static void main(String[] args) {
// 일반고객 테스트
Customer customerLee = new Customer();
customerLee.setCustomerName("이순신");
customerLee.setCustomerID(10010);
customerLee.bonusPoint = 1000;
System.out.println(customerLee.showCustomerInfo());
// vip고객 테스트
vipCustomer customerkim = new vipCustomer();
customerkim.setCustomerName("김유신");
customerkim.setCustomerID(10020);
customerkim.bonusPoint = 10000;
System.out.println(customerkim.showCustomerInfo());
}//////////main
}/////////////////class
위 코드의 출력결과는 어떻게 나올까?
이순신 님의 등급은 SILVER 이고, 보너스 포인트는 1000 입니다. 김유신 님의 등급은 Gold 이고, 보너스 포인트는 10000 입니다.
하위클래스에서 선언하지 않은 상위클래스 내 변수를 어떻게 사용하는 것일까?
상속관계에서는 객체생성시 상위클래스의 생성자가 먼저 호출되고 , 그 다음에 하위클래스 생성자가 호출이된다.
따라서 상위클래스의 생성자가 호출이 먼저 되기때문에 , 상위클래스의 변수가 먼저 메모리할당을 받게되어 하위클래스에서 상위클래스 변수를 사용할 수 있게 되는것이다.
상위클래스(Customer)의 생성자 안에 "상위클래스 생성자 호출합니다."라는 문구를 넣고
하위클래스(vipCustomer)의 생성자 안에 "하위클래스 생성자 호출합니다."라는 문구를 넣어보자그리고 나서 main()에서 하위클래스만 인스턴스화를 하게되면 상위클래스를 인스턴스화 하지 않아도 생성자가 호출되어 문구가 출력되는것을 볼 수 있다.
📍 상위 클래스
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("상위클래스 생성자 호출합니다.");
}
}
📍 하위 클래스
public class vipCustomer extends Customer {
private int agentId; // vip고객 상담원 아이디
double saleRatio; // 할인율
// 디폴트 생성자
public vipCustomer() {
customerGrade = "Gold";
saleRatio = 0.1;
bonusRatio = 0.05;
System.out.println("하위클래스 생성자 호출합니다.");
}
}
📍 main()
public class CustomerTest {
public static void main(String[] args) {
vipCustomer customerkim = new vipCustomer();
customerkim.setCustomerName("김유신");
customerkim.setCustomerID(10020);
customerkim.bonusPoint = 10000;
System.out.println(customerkim.showCustomerInfo());
}//////////main
}/////////////////class
💡 출력결과
상위클래스 생성자 호출합니다. 하위클래스 생성자 호출합니다. 김유신 님의 등급은 Gold 이고, 보너스 포인트는 10000 입니다.
하위클래스는 상위클래스의 주소 즉, 참조값을 알고있다.
이 상위클래스의 참조값을 알고있는 예약어를 super()라고 한다.하위클래스 생성시 자동적으로 상위클래스의 참조값을 담은 super()를 호출하게되므로,따로 super()를 입력하지 않아도, 하위클래스 내 super()가 제일 먼저 자동적으로 생성된다.
하위클래스는 상위클래스의 멤버변수와 메서드를 암묵적으로 갖고오면서, 추가로 더 많은 기능을 넣을 수가 있다.
그러면 하위클래스가 객체생성을 할 때 상위클래스 형태로 생성이 될까?정답은 yes이다. 왜냐하면, 하위클래스는 상위클래스의 모든멤버변수와 메서드를 갖고오면서 더 많은 기능을 추가할 수 있기 때문에 하위 클래스 안에는 상위클래스의 내용을 포함하고 있게되는 것이다.
따라서 상위클래스 형태로 하위클래스 객체생성을 할수가 있는데, 반대로 상위클래스를 하위클래스 형태로 객체생성이 될까?
정답은 no이다. 왜냐하면 상위클래스가 하위클래스의 모든 기능을 갖고있는것은 아니기 때문에 성립이 안된다.
아래 예시를 확인해보자
📍 하위클래스가 상위클래스 형태로 객체생성
Customer c1 = new vipCustemer();
→ 생성이 가능하다
📍 상위클래스가 하위클래스 형태로 객체생성
vipCustomer c2 = new Customer();
→ 생성이 불가능하다.
하위클래스가 상위클래스 형태로 객체생성이되면, 상위클래스가 가진 멤버변수와 메서드만 사용이 가능하다.