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(); };
}
'교육 > Java&Spring' 카테고리의 다른 글
kosta 클라우드 네이티브 애플리케이션 개발 과정 day 14 (0) | 2023.01.06 |
---|---|
kosta 클라우드 네이티브 애플리케이션 개발 과정 day 13 (0) | 2023.01.05 |
kosta 클라우드 네이티브 애플리케이션 개발 과정 day 11 (0) | 2023.01.03 |
kosta 클라우드 네이티브 애플리케이션 개발 과정 day 10 (0) | 2023.01.02 |
java & spring 2 (1) | 2022.12.31 |