상속은 좀 더 일반적인 클래스가 있고 이것보다 좀 더 기능이 구체적인 클래스를 설계 한다.
유사한 클래스를 만드는데 기존의 클래스를 가져다가 좀 더 확장된 클래스를 만들 때 상속을 사용 한다.
Customer 상위클래스, VIPCustomer 하위클래스
하위클래스가 생성되는 과정
class Person{
String name;
public void work(){
System.out.println("일하기");
}
public void sleep(){
System.out.println("잠자기");
}
}
// person을 상속하는 자식 클래스 extends 키워드를 이용하여 상속
class Developer extends Person{
String mainLang;
public void writeCode(){
System.out.println("돈 받은 만큼 코딩하기");
}
}
class Student extends Person{
String major;
public void writeCode(){
System.out.println("밤새 코딩하기");
}
}
// 메인머신 'HAS-A' String 이미 스트링을 컴포지션하고 있었다.
class MainMachine{
String model;
boolean isBroken = false;
public MainMachine(String model){
this.model = model;
}
}
// developer 'HAS-A; MainMachine 개발자클래스가 메인머신의 객체 하나를 보유한다.
// 보유하고 있어서 메인머신의 속성을 건드릴 수 있다.
class Developer{
String name;
MainMachine mainMachine;
public Developer(String name,MainMachine machine){
this.name = name;
this. mainMachine = machine;
}
public void writeCode(){
if(mainMachine.isBroken) {
System.out.println("코딩할 수 없습니다.");
}else{
System.out.println(mainMachine.model+ "으로 코딩하기");
}
if(Math.random() > 0.9){
breakMachine();
}
}
public void breakMachine(){
mainMachine.isBroken = true;
}
}
MainMachine mac = new MainMachine("MacBook Pro");
Developer dev = new Developer("나개발",mac); // 메인머신을
// dev.mainMachine.model 가능
// dev.model 불가능.
// 일치하냐 보유하냐의 차이 (상속과 컴포지션의 차이)
for (int i =0; i<10; i++){
dev.writeCode();
}
class Person{
public void writeCode(){
System.out.println("아무 코드나 일단 적어 보았다.");
}
}
class Student extends Person{
@Override // 이렇게 적어주는 것이 관례 필수는 아님(문법 오류는 아님) @ - 에노테이션
public void writeCode(){
System.out.println("능숙하게 코드를 작성해 보았다.");
System.out.println("답은 틀렸다.");
System.out.println("하지만 무언가 또 배웠다.");
}
}
class Developer extends Person{
@Override // 다양하게 오버라이드 될 수 있음.
public void writeCode(){
System.out.println("코드 작성이 하기 싫어서 하지 않았다.");
}
}
Customer vc = new VIPCustomer();
vc.calcPrice(10000);
위 코드에서 calcPrice()
메소드는 어느 메소드에서 호출 될까?
자바에서 항상 인스턴스의 메소드가 호출이 된다. (메모리의 자료형을 따라서 메소드가 호출이된다.)
그 이유는 Virtual method Call
이 이루어지기 때문이다.
public class Customer {
protected int customerID;
protected String customerName;
protected String customerGrade;
int bonusPoint; // 보너스 포인트
double bonusRatio; //보너스 포인트 적립 비율
public Customer(){ //생성자를 기본 초기값으로 설정해주듯이 사용하면 될 것 같다.
customerGrade = "Silver";
bonusRatio = 0.01; //1%로 적립
System.out.println("customer 생성자 호출");
}
public Customer(int customerID,String customerName){
this.customerID = customerID;
this.customerName = customerName;
customerGrade = "Silver";
bonusRatio = 0.01; //1%로 적립
System.out.println("customer 파라미터 생성자 호출");
}
public String showCustomerInfo(){
return customerName+"님의 등급은 "+customerGrade+"이며, 적립된 보너스 포인트는 "+bonusPoint+"점 입니다.";
}
public int calcPrice(int price){ //지불할 가격 반환.
bonusPoint += price * bonusRatio;
return price;
}
}
Customer customerLee = new Customer(10010,"이순신");
customerLee.bonusPoint=1000;
VIPCustomer customerKim = new VIPCustomer(10020,"김유신");
customerKim.bonusPoint = 10000;
int priceLee = customerLee.calcPrice(10000);
int priceKim = customerKim.calcPrice(10000);
System.out.println(customerLee.showCustomerInfo() +"지불금액은 "+priceLee);
//이순신님의 등급은 Silver이며, 적립된 보너스 포인트는 1100점 입니다. 지불금액은 10000
System.out.println(customerKim.showCustomerInfo()+"지불금액은 "+priceKim);
//김유신님의 등급은 VIP이며, 적립된 보너스 포인트는 10500점 입니다. 지불금액은 9000
Customer customerNo = new VIPCustomer(10030,"나몰라");
customerNo.bonusPoint=10000;
System.out.println(customerNo.showCustomerInfo()+"지불금액은 "+customerNo.calcPrice(10000));
// 나몰라님의 등급은 VIP이며, 적립된 보너스 포인트는 10000점 입니다. 지불금액은 9000
// 지불금액이 예상하기로 10000이 나와야하지만 결과는 9000이나옴
// 이유는 vipcustomer의 calcPrice()메소드가 호출되었기 때문에
// 이것을 가상메소드호출이라 한다.
class Foo {
String x = "Foo";
public Foo(String x) {
this.x = x;
}
}
class Bar extends Foo {
String x = "Bar";
// 멤버 변수명이 부모와 겹치면 재정의 하지만 부모가 사라지는 것은 아님.
// 부모클래스에 기본 생성자를 사용하는 경우에는 호출 안해주어도 된다.
// 부모클래스에 파라미터 생성자가 있으면 호출해 줘야 한다. super 사용.
public Bar(String x, String x1) {
// 부모클래스 생성자와 다르게 파라미터 변수명을 다르게 해줘야 한다. x,x1
super(x); //this와 마찬가지로 첫줄에 써야한다. 부모클래스 생성자 호출.
//부모 객체를 먼저 생성하고, 그 다음에 자식 객체를 생성.
this.x = x1; //자식클래스 생성자를 만들때 부모클래스 생성자도 같이 호출해줘야한다.
}
public void method(){
//로컬변수명과 멤버변수명은 같을 수 있다.
// String x = "method"; 로컬변수가 없어지면 멤버변수를 참조,
// 멤버변수도 없어지면 super클래스의 변수사용.
System.out.println(x);
// 로컬변수 -> 멤버변수 -> 부모의 멤버변수 순으로 접근
System.out.println(this.x);
// 자기 자신의 객체에 접근가능 멤버변수 - > 부모의 멤버변수
System.out.println(super.x); // 부모 객체에 접근 가능 부모의 멤버변수
}
}