상속은 객체 지향프로그래밍에 특징 중에 하나로 어떤 클래스보다 좀 더 확장된 기능을 구현하고 싶을 때 새로 클래스를 구현하는게 아니라 이미 구현된 클래스를 상속받아서 속성이나 기능 확장시킨 클래스를 구현하는 것을 말합니다.
코드의 재사용의 개념이 아닌 기존의 클래스를 가져다가 좀더 확장된 기능을 만드는 것을 뜻하고 이질적인 기능을 하는 클래스간에는 상속의 개념을 사용할 수 없습니다.
상속하는 클래스는 상위 클래스, parent class, base calss, super class라는 용어를 사용합니다.
상속받는 클래스는 하위 클래스, child class, de rived class, sub class라는 용어를 사용합니다.
B가 A로부터 상속받는 경우 B class exteds A{ }라고 표현하고 Java에서는 A의 자리의 하나의 클래스만 들어갈 수 있는 single inheritance만 가능합니다.
아래 그림과 같이 박스로 많이 표현하고 화살표의 방향이 상속받는 쪽이아닌 상속하는 쪽을 향하게 해서 화살표 내부를 비워놓고 표현하는 경우가 많습니다.
상위 클래스는 하위클래스보다 일반적인 개념과 기능을 가지고 하위클래스는 상위 클래스보다 구체적인 개념과 기능을 가집니다.
포유류 <- 사람의 경우에서 포유르는 더 포괄적인 개념으로 사람뿐만아니라 침팬지, 고릴라, 팬더 등 다른 포유류들로 분화될 수 있는 것 같이 일반적인 상위클래스는 구체적인 여러 하위 클래스들로 세분화 될 수 있습니다.
위의 관계를 코드로 나타내면 Class Mammal {} class Human extends Mammal {}와 같습니다.
고객에 등급에 따라 차별화된 서비스를 제공할 수 있습니다.
고객의 등급에 따라 할인율, 적립금이 다르게 적용됩니다.
이러한 경우에 대하여 구현을 해보도록 합시다.
public class Customer {
//1번
private String customerId;
private String customerName;
private String customerGrade;
int bonusPoint;
double bonusRatio;
//2번
public Customer() {
customerGrade = "silver";
bonusRatio = 0.01;
}
//3번
public int calPrice (int price) {
bonusPoint += price * bonusRatio;
return price;
}
//4번
public String showCustomerInfo( ) {
return customerName + "님의 등급은 "+customerGrade+"이며, 적립된 보너스 포인트는 "+bonusPoint+"점 입니다";
}
//5번
public String getCustomerId() {
return customerId;
}
public void setCustomerId(String 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;
}
}
1번 : Customer 클래스를 생성하고 조건에 맞는 멤버 변수들을 먼저 선언해 줍니다.
2번 : Customer 생성자를 만들면서 cutomerGrade와 bonusRatio에 초기화하는 값을 입력합니다. 보통 생성자를 통해서 초기값을 입력하게 됩니다.
3번 : calPrice를 메서들 만들어 price를 입력하면 bonusPoint를 계산해서 넣고 다시 price를 retrun하도록 합니다.
4번 : showCustoemrInfo를 만들어서 고객의 현재 정보를 출력할 수 있도록 합니다.
5번: private 멤버변수를 읽고 쓰기 위한 getter/setter 를 만들어 줍니다.
VIPCustomer 클래스의 기능
: 제품 구매시 10% 할인
보너스 포인트 5% 적립
담당 상담원 배정
=> Customer 클래스와 유사하지만, 그보다 더 많은 속성과 기능을 필요
그림으로 표현하면 다음과 같다
//1번
public class VIPCustomer extends Customer {
public int agentID;
public double salesRatio;
//2번
public VIPCustomer () {
salesRatio = 0.1;
bonusRatio = 0.05;
customerGrade = "VIP";
}
}
VIPCustomer 클래스는 Customer 클래스의 멤버 변수와 메서드를 사용하면서 추가적인 기능을 하기 때문에 Custoemr class 란에 extends를 써서 Customer를 상속받도록하고 추가된 멤버 변수만 넣어 줍니다.
2번 상속자에 Vip클래스에서 바뀐 초기값들을 넣어주면 Cusomer클래스에서 가져온 custoemerGrade가 오류가 나는데 접근제한자가 private으로 되어있기 때문입니다. 이때 사용할 수 있는 것이 protected 접근제한자로 외부에선 접근을 막지만 하위 클래스에선 접근이 가능하도록 해주는 역할을 하기 때문입니다.
public class Customer {
protected String customerId;
protected String customerName;
protected String customerGrade;
Customer 클래스의 멤버 변수를 다음과 같이 바꾸어 주면 오류가 사라지고 사용이 가능해집니다.
접근제어자(access modifier)의 가시성
잠시 접근제어자에 대해 정리하고 넘어가자면 public > protected > 선언되지않음(default) > private순으로 공개되는 범위가 넓어지는 것을 알 수 있습니다.
public class CustomerTest {
public static void main(String[] args) {
//1번
Customer Lee = new Customer();
Lee.setCustomerId(10010);
Lee.setCustomerName("이순신");
Lee.bonusPoint= 1000;
System.out.println(Lee.showCustomerInfo());
//이순신님의 등급은 silver이며, 적립된 보너스 포인트는 1000점 입니다
//2번
VIPCustomer Kim = new VIPCustomer();
Kim.setCustomerId(10020);
Kim.setCustomerName("김유신");
Kim.bonusPoint = 10000;
System.out.println(Kim.showCustomerInfo());
//김유신님의 등급은 VIP이며, 적립된 보너스 포인트는 10000점 입니다
}
}
1번 : 일반 고객 Customer Lee를 생성하고 protected 변수는 set메서드를 사용해서 갑을 입력하고 아닌것은 바로 대입해줍니다. showCustoemrInfo 메서드를 출력하면 등급이 silver로 잘나오는 것을 알 수 있습니다.
2번 : VIP 고객 VIPCustomer Kim을 생성하고 똑같이 입력해 줍니다. 마찬가지로 shoCustomerInfo를 사용해서 출력하면 VIP등급의 고객이 출력되는 것을 확인할 수 있습니다.
이처럼 상속받은 클래스에서 상위 클래스에 변수와 메서드를 사용할 수 있는 것을 확인해보았습니다.