본문 바로가기
교육/Java&Spring

kosta 클라우드 네이티브 애플리케이션 개발 과정 day 12

by Renechoi 2023. 1. 4.

kosta 클라우드 네이티브 애플리케이션 개발 과정 day 12


 

상속에 대해 배워보자 ! 

 

확장성 ! 

 

-> 상속을 통해 확장성을 이해할 수 있다. 

-> 계좌의 기능 -> 확장 -> 직불카드... 기능 ! 

 

계좌

- 계좌번호

- 예금주 이름

- 잔액

- 예금한다

- 인출한다 

 

=> 확장 

 

직불 계좌 

(- 계좌번호)

(- 예금주 이름)

(- 잔액)

- 직불카드 번호

(- 예금하다)

(- 인출하다)

- 직불카드 사용액을 지불한다

 

상속이 필요한 경우 

- 기존 클래스와 유사한 클래스를 만들어야 할 경우 

 

 

현실세계에서는 부모를 고를 수가 없다!

하지만 자바의 세계에서는 가능하다! 

 

상속의 경제적 측면

-> 기능적으로 부모의 메서드를 사용할 수 있다. 

 

상속의 사회적 측면

-> 변수, 메서드를 쓰는 것 이상의 의미 

-> e.g. checkingAccount가 Account를 상속한다면 데이터 타입을 Account로 사용할 수 있다 ! 

=> 캐스팅 등의 활용이 가능 ! 

 


class Person extends Car{}

 

이와 같은 선언은 어떨까? 

 

문법적으로 문제는 없지만... ? 

 

Person의 부모가 Car이다 => 이상한 개념이 되어버린다. 

 

rather -> class Truck extends Car {}

 


 

자식 클래스를 생성하면 먼저 부모 클래스가 생성된다. 

super()를 통한 부모 생성 

 

package kosta.mission2.Mission2_10.bank.customer;

import kosta.mission2.Mission2_10.bank.ui.OutputView;

public class CheckingAccount extends Account {

    private String checkingAccountNo;

    public CheckingAccount() {
    }

    public CheckingAccount(String id, long balance) {
        super(id, balance);
        this.checkingAccountNo = super.getId();
    }

    public void payDebitCard(String checkingAccountNo, long amount) {
        if (this.checkingAccountNo.equals(checkingAccountNo)){
            super.withdraw(amount);
            OutputView.consolePrint(OutputView.PAYMENT_SUCCESS);
            return;
        }
        OutputView.consolePrint(OutputView.PAYMENT_NOT_SUCCESS);
    }
}

 


정리 ! 

 

- 클래스의 확장을 위해서 상속을 활용한다. 

- 상속은 extends 키워드를 통해 구현한다.

- 상속을 하면 부모의 필드, 메서드를 자식에서 사용할 수 있다. 

- 자식이 생성될 때 부모가 생성된다. 

- 부모의 생성자를 자동으로 호출되고 이때 default 생성자가 호출된다. 

- super()를 이용해 원하는 부모 생성자를 호출할 수 있다. 

=> 이때 파라미터 값을 전달해서 생성하여 활용할 수 있다. 

 

 


오버로딩 vs 오버라이딩 

 

오버로딩 = 메서드에서 

오버라이딩 => 상속, object 형변환, 인터페이스, 다형성에서 

 

 

상속 클래스에서 오버라이딩을 왜 쓸까? 

- 해당하는 부모클래스의 내용이 만족스럽지 못할 경우 

 

마이너스 통장을 만든다고 해보자. 

 

기존의 account 클래스

- 계좌번호

- 이름

- 잔액

- 예금한다

- 인출한다 

 

마이너스 통장 계좌 

- 마이너스 한도 (추가) 

- 인출한다 (상속 받으면 안 됨!) 

 

=> 즉 새로운 메서드가 필요하다

=> 오버라이딩 : 슈퍼클래스와 똑같은 시그니쳐를 갖는 메서드를 자식 클래스에 선언하되 다른 기능으로 구현 ! 

 

오버라이딩의 조건

- 상속 관계 (여기의 예에서) 

- 부모의 메서드를 자식 클래스에서 사용하기 부적합할 때  

- 자식 메서드가 부모의 메서드 시그너처와 일치 => 접근제어자, 리턴형, 메서드명, 파라미터 

 

 

package kosta.basic.day012.overidingExample;

import kosta.basic.day007.Account;

public class MinusAccount extends Account {

    private int creditLimit;

    public MinusAccount(){
    }

    public MinusAccount(String accountNo, String ownerName, int balance, int creditLimit) {
        super(accountNo, ownerName, balance);
        this.creditLimit = creditLimit;
    }


}

 

계좌 한도를 설정했는데 account의 withdraw를 그대로 사용하는 것이 맞지 않다 ! 

 

@Override
public void withdraw(int amount) {
    if (getBalance() + creditLimit < amount) {
        throw new IllegalArgumentException("마이너스 한도 초과!");
    }
    setBalance(getBalance() - amount);
}

 

 


 

 

오버라이딩 된 메서드를 갖고 호출할 경우 

부모의 것이 아닌 자기 자신 것이 호출된다. 

 

 

생성자에서 super() => 자식의 생성자에서 부모의 생성자를 호출하기 위함 

overriding method에서 사용하는 super => 다시 부모의 메서드를 호출하고 싶을 때 (this => super) 

 

 

 


java Object의 equals 메서드 

 

암묵적 상속을 받는 object 클래스의 equals 메서드를 오버라이딩 할 수 있다. 

 

언제 equals를 재정의해야 할까? 

 

같은 필드 밸류를 주더라도 new로 만든 두 객체는 서로 다른 주소값을 가지므로 equal에서 false를 리턴한다. 

 

Video video1 = new Video("술도녀", new Actor("이선빈"));
Video video1 = new Video("술도녀", new Actor("이선빈"));

=> 두 객체는 다름 ! 

 

이때 true를 리턴하고자 한다면 (속성들에 대한 비교) 

equals를 다음과 같이 재정의 한다. 

 

    @Override
    public boolean equals(Object o) {
        if (this == o)
            return true;
        if (!(o instanceof Video))
            return false;
        Video video = (Video)o;
        return name == video.name &&
            Objects.equals(name, actor);
    }

 

그렇지 않으면 오직 자기 자신과만 true 관계를 가진다. 

 

hashCode 메서드도 재정의해주어야 한다. 

 

hashCode를 재정의하지 않으면 equals를 통해 같은 것으로 판단된 객체라 할지라도 서로 다른 hashCode 값을 가진 것으로 리턴할 수 있다. => 여기서 발생하는 문제는 hashTable에서 해당 객체가 저장된 버킷을 찾을 수 없게 되어 nullPointerException을 반환하게 된다는 것이다. 

 

 

    @Override
    public int hashCode() {
        return Objects.hash(name, actor);
    }

Object 형변환 

 

Object도 캐스팅을 할 수 있다. 필요로 한다. 

 

왜 ? 


General Member와 Special Member가 있다고 할 때 이들을 한 곳에 모아야 하는 경우가 있다. 

이때 기존의 Member 객체만 있었다면 Member[] 배열을 사용하면 되지만, 두 개의 다른 object 타입을 한 곳에 모으는 방법으로는 다른 방법이 필요로 한다. 

 

e.g. 

List 컬렉션을 생각해보자. add method를 사용할 때 generic으로 받고 있는 것을 볼 수 있다. 

 

 

 

=> 형변환의 필요성 !!! 

 

그렇다면 casting의 기준을 어떻게 할까? 

=> 가장 상위 클래스 = Object 

=> 모든 클래스는 Object를 상속받고 있기 때문에 (Object) 형변환이 가능하다. 

 

 

상위 클래스로의 호환이 가능하기 때문에 

이와 같은 타입 변환이 가능하다.

 

Video movie = Video.valueOf("아이언맨", new Actor("로다주"), "movie");
System.out.println(movie);

member.watchVideo(movie);

 

 

 

Account minusAccount2 = new MinusAccount("111","박길동",1000, 3000);
System.out.println(minusAccount2.getClass());
System.out.println(minusAccount2.getClass().getSimpleName());
System.out.println(minusAccount2.getClass().getName());
System.out.println(minusAccount2.getClass().getConstructors());
System.out.println(minusAccount2.getClass().getTypeName());
System.out.println(minusAccount2.getClass().getSuperclass());
System.out.println(minusAccount2.getClass().getGenericSuperclass());

 

=> 부모로는 형변환이 가능하다. 

 


그런데 이렇게 캐스팅을 했을때 문제점이 무엇일까? 

 

기존에 자식 클래스에만 있던 메서드를 상위 타입으로 캐스팅된 상태라면 해당 메서드를 호출하지 못한다 ! (런타임 exception으로 casting exception을 발생시킴) 

 

따라서 이를 다시 활용하려면 부모 타입을 다시 자식 타입으로 바꿔주어야 하는데 

 

이때 묵시적 형변환이 불가능하므로 강제 형변환을 시켜준다 

 

CheckAccount checkAccount = (CheckAccount) account; 

 


형변환이 가능한지 여부를 체크해주는 연산자로 instanceOf를 사용한다. 

 

형변환이 가능한지 불리언 값을 리턴해줌 

 

GeneralMember generalMember1 = new GeneralMember("a", "홍길동", "가산");

if (generalMember instanceof SpecialMember){
    SpecialMember specialMember1 = (SpecialMember) generalMember1;
}

 

그런데 인텔리제이는 이걸 알려준다. 

 

 


 

자바의 다형성에 대해 배워보자! 

 

도형[] arr = { new 삼각형, new 사각형, new 원 }

for (도형 도형 : arr) {
 도형.draw()
 }

 

draw 메서드를 호출했을 때 각각의 도형들의 모양을 그리게 된다. 

=> override를 통한 다형성 구현 

 

* 추상클래스와 인터페이스는 overriding을 강제하므로 반드시 해당 메서드가 존재한다는 것을 보장한다 ! 

 

public class shape{
  
  public draw(){}
}
  
  
public class triangle extends shape{
  
   @Override
   draw(){}
}



public static void main(){
   
   Shape[] arr = { new triangle();        }; 
 
}
반응형