본문 바로가기

Programming language/Java

Java - 9 [상속, super]

상속

- 상속이란 기존의 클래스를 모두 받고 이어서 확장시켜 새로운 클래스를 정의하는 개념이다.

- 자동차라는 클래스가 있다면 트럭이라는 클래스는 자동차라는 클래스를 상속받아 확장한 클래스이다.

이때 상속받은 클래스는 자식클래스 모태가 되는 클래스는 부모클래스 라고 한다.

 

public class BankAccount {
    private int balance;

    public int getBalance() { 
        return balance; 
    }

    public void setBalance(int balance) {
        this.balance = balance;
    }

    // 출금
    public boolean withdraw(int amount) {
        if (balance >= amount) {
            balance -= amount;
            return true;
        }

        return false
    }

    // 입금
    public boolean deposit(int amount) {
        balance += amount;
        return true;
    }
}

- 위와 같은 Bank클래스를 확장시켜 SavingAccount라는 새로운 클래스를 선언했다.

이 클래스는 Bank클래스를 상속 받은 것이다. 상속 받을 때는 어떤 클래스를 상속받았는지 명시하기 위해서

extends 부모클래스  라는 키워드를 붙여야 한다.

public class SavingsAccount extends BankAccount {
    private double interest;

    public void setInterest(double interest) {
        this.interest = interest;
    }

    public double getInterest() {
        return interest;
    }

    public void addInterest() {
        setBalance((int) (getBalance() * (1 + interest)));
    }
}

Bank를 상속받은 MinimumBalanceAccount 를 선언하면

public class MinimumBalanceAccount extends BankAccount {
    private int minimum;

    public void setMinimum(int minimum) {
        this.minimum = minimum;
    }

    public int getMinimum() {
        return minimum;
    }

    @Override
    public boolean withdraw(int amount) {
        if (getBalance() - amount < minimum) {
            System.out.println("적어도 " + minimum + "원은 남겨야 합니다.");
            return false;
        }

        setBalance(getBalance() - amount);
        return true;
    }
}

위 와 같이 나타는데 이중 

@Override 태그를 단 메소드가 있다.

withdraw메소드는 부모클래스인 Bank 클래스에도 있던 메소드인데

이메소드를 약간 다르게 변형시켜 받기 위해서 오버라이드

한것이다.

 

이렇게 부모클래스의 메소드를 다시 정의하는 과정을 오버라이드라고한다.

 

간혹 같은 메소드를 인수만 바꾸어 선언하여 구분하는 오버로드 와 헷갈리는 경우가 있으니

조심하자.

 

Super

- 부모클래스를 상속받은 자식클래스에서 사용한다.

 

1. 자식클래스가 부모클래스의 변수, 메소드를 사용할때,

public class TransferLimitAccount extends BankAccount {
    private int transferLimit;

    @Override
    boolean withdraw(int amount) {
        if (amount > transferLimit) {
            return false;
        }

        return super.withdraw(amount);
    }
}

이렇게 super.withdraw(amount);부분을 보면 이부분에서 사용되는 withdraw는 현재 재정의되어 오버라이드하는 withdraw가 아니라 원래 부모클래스에서 동작하는 withdraw를 나타내는 것이다.

 

즉, 원래 부모클래스에서 사용하는 기능을 가진 부모클래스의 메소드를 사용하고 싶다면 super라는 키워드로 메소드를 호출 하면된다.

 

2. 자식클래스가 부모클래스의 생성자를 사용할 때,

public class TransferLimitAccount extends BankAccount {
    ...
    public TransferLimitAccount(int balance, int transferLimit) {
        super(balance);
        this.transferLimit = transferLimit;
    }
}

위 코드에서 super(balance)는 부모클래스에서 생성자안에서 정의되었던 변수이다.

따라서 똑같은 코드를 쓰는 것이므로 super키워드로 부모클래스에서 balance코드를 불러오는 것이다.

 

super 키워드를 생성자에서 사용할 때 규칙

1. 먼저 자식클래스의 인스턴스 생성시 부모클래스의 기본생성자(인수가 없는 생성자)도 함께불린다.

즉, 상속된 부모클래스의 부모클래스의 생성자도 불리게되며 상속된 맨위 클래스의 생성자 까지 다 불립니다.

Child c = new Child();

2. 자식클래스가 부모클래스의 생성자를 부를때는 항상 자식클래스의 맨위에 호출해야한다.

그 어떤 부모생성자를 호출하던 반드시 맨위에 호출해야한다.  

 

3. 부모클래스에 인수가 없는 생성자(기본생성자)가 없고 인수가 있는 생성자만 있을경우 반드시

자식클래스에서 부모클래스의 생성자를 호출해주어야한다.

 

public class Parent {
    // 별도로 생성자가 지정되어있는 경우 (파라미터 없는 기본 생성자가 없는 경우)
    public Parent(int a, int b) {
        ...
    }
    ...
}
    
public class Child extends Parent {
    public Child() {
    	// 맨위에 안적으면 에러메세지!
        super(0, 0); // 자식 클래스에 생성자를 만들어 'super(int, int)'를 호출해 주어야 함
        ...
    }
}