
ㅎㅇ
대관령 여행가기로 했는데 차표가 없어서 못 감 미리 예매좀해둘걸
암튼 주말에는 서울 한 번 가보도록 하고... 신나게 책이나 읽읍시다.
다형성 계획에 참여하기 전까지는 우리도 저임금과 야근에 시달리는 코더(coder)에 불과했습니다. 하지만 그 계획 덕분에 우리의 미래가 밝아졌죠. 여러분도 다형성을 배우고 나면 세상이 달라 보일 거예요.
상속은 컴퓨터공학개론에서 파이썬으로 한 적 있다. 자바에서도 크게 다르지는 않을 거라고 생각된다.
근데 사실 컴공개 때 수업을 잘 안들어서.. 교수님 죄송합니다
용어정리
내용정리
상속
상속이란 객체들 간의 관계를 구축하는 방법이다. (위키백과)
말이 너무 추상적이라 약간 나의 언어로 풀이를 해보자면.. 상속이란 한 클래스에서 코드를 작성하고 다른 클래스에서 이를 물려받아 사용하는 것을 뜻한다고 생각된다. 이 때 다른 클래스는 여러 개일 수 있다.
코드를 물려주는 클래스는 상위클래스, 코드를 물려받는 클래스를 하위클래스라고하며, 하위클래스가 상위클래스로부터 상속받는다고 상속을 표현할 수 있지만, 자바에서는 하위클래스가 상위클래스를 확장(extend)한다라고 한다. 이 때 하위클래스에서 인스턴스 변수나 메서드를 추가해도 된다.
상속을 이용할 때는 공통된 코드를 한 클래스에 넣고 더 구체적인 클래스가 하위로 가도록 설정하면 된다.
하위클래스는 상위클래스의 메서드, 인스턴스 변수들을 그대로 가져온다. 이때 하위클래스에서 상위클래스에서의 메서드를 변경할 필요가 있어 상속받은 메서드를 새로 정의하는 것을 오버라이딩(오버라이드) 이라고 한다. 인스턴스 변수는 오버라이드할 수 없다.
상속의 장점
당연하지만 코드중복을 방지하고 공통적인 프로토콜을 가지게 된다. 수정할 때도 공통된 코드 한 부분만 고치면 상속받은 클래스에서 변동사항이 자동반영된다.
상속하기
자세한 설명은 헤드퍼스트자바 7장 214쪽부터 읽으면 좋다.
1. 공통적인 속성, 행동을 찾기
2. 1에서 찾은 공통적 속성, 행동을 나타내는 클래스 설계
3. 하위클래스에서 특정클래스에만 적용되는 메서드가 필요한지 결정하고 오버라이드
4. 하위클래스에서 공통적인 행동이 필요한 하위클래스를 찾아서 추상화의 개념 넓히기
5. 4에서 찾은 하위클래스들로 새로운 상위클래스를 만들기 (즉, 기존 하위클래스의 상위클래스의 하위클래스이자 기존 하위클래스의 상위클래스로)
이렇게
상위클래스
|
하위클래스1
|
하위클래스2
구조에서 메서드를 호출할 시, 가장 하위에 있는 클래스의 메서드가 호출된다.
JVM에서는 가장 하위의 클래스부터 상위로 올라가며 메서드를 찾는다.
오버라이드를하면서 기존 상위클래스의 메서드가 필요할 때는 다음과 같이 상위클래스의 메서드를 호출할 수 잇다.
public class nmae extends supernmae {
public void roam() {
super.roam(); //상위클래스의 메서드 호출
}
}
super.(메서드이름)(); 이런 식으로
이중상속
상위 - 하위 - 하위하위 순으로 상속될 때, 하위클래스에 없는 메서드는 가장 가까운 상위클래스에서 메서드를 찾는다.
어떻게 확장여부를 정할까?
자세한 예시는 헤드퍼스트자바 7장 221페이지를 참고하면 좋다.
A는 B이다
A는 B이다 라는 문장을 만들었을 때 문장이 어색하지 않으면 옳은 상속관계이며, 약간이라도 어색할 경우에는 상속관계가 아니다. 이때 B는 A를 확장한다고 할 수 있다. (B가 하위클래스) 즉, A는 B이다 = B가 A를 확장한다/상속한다.
이는 아무 상위클래스-하위클래스에 대입했을 때 성립해야한다. 위의 구조에서 하위클래스2는 하위클래스1과 상위클래스에 대해서 A는 B이다가 성립해야한다.
A는 B이다는 단방향으로만 작동한다. B는 A다는 성립하지 않는다.
컴공개 때 배운 is-a 관계
A에는 B가 있다
A에 B가 있다가 성립되면 B는 A의 인스턴스변수로 들어가야한다. 확장/상속관계로는 설계될 수 없다.
컴공개 때 배운 has-a 관
상속설정
상위클래스는 변수에 접근단계를 지정해서 하위클래스에서 상속여부를 따질 수 있다. 접근단계는 접근이 제한된 것부터
private
default
protected
public
책에서는 private로 지정된 멤버는 상속되지않는다
default는 해당 패키지 내에서만
protected는 동일패키지 또는 자식클래스에서 접근 가능하다.
final로 지정하면 확장할 수 없다.
상속 시 주의점
- 한 클래스가 타 클래스를 구체화한 버전이면 상속을 활용한다.
- 상속만이 최선의 방법은 아니다. (책 추천 : 헤드퍼스트 디자인 패턴(한빛미디어))
- 코드 재사용을 목적으로 상속을 써서는 안된다. (A는 B다 관계 이용하기)
다형성
우선 다형성에 대해 알기 전에 레퍼런스 변수의 선언과 설정에 대해 알아보기로 했다.
User user = new User();
스프링 DI를 사용하는 것과는 다르지만 우선 알아보자면..
User user
이 부분에서 JVM에게 User type에 해당하는 변수를 저장할 공간을 할당하도록 지시한다. 레퍼런스 변수의 타입은 변하지 않는다.
new User();
새 User 객체를 형성한다.
User user = new User();
새로 만들어진 User 객체를 user 레퍼런스변수에 대입한다. 이 때부터 user는 새 User 객체를 참조하게 된다.
이 때 레퍼런스 객체의 타입과 객체의 타입이 일치해야한다.
다형성은 레퍼런스 변수를 선언할 때, 레퍼런스 변수를 대입할 클래스의 상위클래스로 선언할 수 있다는 것이다.
Animal animals = new Animal[3];
Animals[0] = new Dog();
Animals[1] = new Cat();
Animals[2] = new Lion();
for (Animal animal : animals) {
animal.eat();
animal.roam();
}
(출처 : 헤드퍼스트자바 7장 230페이지 코드. 문제시 삭제)
이렇게되면 반복문을 도는동안 i가 0일 경우에 Dog 클래스의 eat 메서드를 호출하고, 1일 경우 Cat 클래스의 eat 메서드를 호출하고.. 이런식으로 진행된다.
class Noise {
public void NoiseMaker(Animal a) {
a.makenoise();
}
}
Dog dog = new Dog();
Lion lion = new Lion();
dog.makeNoise();
lion.makeNoist();
이렇게 인자로 전해줄 수도 있다.
즉, 클래스의 상위클래스를 레퍼런스변수로 선언할 수 있으며, 레퍼런스변수가 호출될 경우 type이 호출된 클래스던 그 클래스의 상위클래스던 호출된 클래스로 잘 동작한다.
여기서 상속 / 다형성의 장점인 수정용이 이런게 나온다.
만약 상속을 쓰지 않았는데 Tiger를 추가한다면? 우선 Tiger에 대해 또 roam 메서드와 eat 메서드를 만들어야하고 Noise 클래스를 다른 사람이 짤 경우 그 사람은 내 Tiger에 대해 알고 코드를 짜야하지만, 저렇게 Animal로 선언을해두고 Tiger를 Animal에서 확장을 시켜놓으면 Noise 클래스에서는 딱히 더 알아야할게 없다. Animal 클래스에서 다 처리해주기 때문이다.
오버라이드 규칙
메서드는 계약서입니다.
메서드를 논리구조, 로직, 함수 등으로 접근하는 일이 있었는데 DDD시작하기에서나 여기에서나 규칙, 계약서, 규정 등으로 정의하는 것을 보면 그런 시각에서 바라보는게 더 나을 것 같다.
아까 Animal 과 Dog 코드에서..
Animal은 eat, roam 메서드를 가지고 있다고하고
Animal 클래스를 상속한 Dog도 eat, roam 메서드가 있다고 쳤을 때, Dog의 eat 메서드에 boolean isFull을 받는다면? 오버라이드가 아니다. 상속받은 클래스는 인자를 변경할 수 없다.
Animal animal = new Dog();
.
.
.
animal.eat();
이렇게 되면 animal.eat()에서 정상적인 상속의 경우에는 Dog 객체의 eat 메서드가 호출되어야하나 Dog의 eat 메서드가 인자를 받아버려 상속관계에서 벗어나게 되었다. 이렇게되면 Animal 클래스의 eat 메서드가 호출된다.
규칙
받는 인자는 같아야하며 리턴 타입은 호환가능(같거나 하위클래스) 해야한다.
하위클래스의 접근단계는 상위클래스와 같거나 완화되어야한다.
오버로딩
Spawn more Overload(ing)s
오버로드, 오버로딩은 그냥 같은 이름을 가졌지만 반환타입만 다른 두 메서드를 만드는 것을 뜻한다.
public int adding(int a, int b){
return a + b;
}
public float adding(float a, float b){
return a + b;
}
이런식으로..
단, 인자에서 받는 값의 타입도 바꿔야한다. 바꾸지 않을경우 컴파일러가 오버라이드하는 것으로 간주하며, return 타입이 호환불가 시 오류도 발생한다.
접근단계 변경은 큰상관없다.
소감
'언어공부 > Java | Kotlin' 카테고리의 다른 글
| [2025백엔드] 헤드퍼스트자바 독서 #6 - 10장. 숫자는 정말 중요합니다 (5) | 2025.08.03 |
|---|---|
| [2025백엔드] 헤드퍼스트자바 독서 #5 - 9장. 객체의 삶과 죽음 (3) | 2025.07.27 |
| [2025백엔드] 헤드퍼스트자바 독서 #4 - 8장. 심각한 다형성 (2) | 2025.07.26 |
| [2025백엔드] 헤드퍼스트자바 독서 #2 - 6장. 자바 라이브러리 사용하기 (3) | 2025.07.24 |
| [2025 백엔드] 헤드퍼스트자바 독서 #1 - 5장. 메서드를 더 강력하게 (2) | 2025.07.23 |