티스토리 뷰
포스팅에 앞서 내용이 틀릴 수 있습니다.
해당 부분 지적 감사히 받습니다.
드디어 기다리던 상속 파트이다.
자바에서 굉장히 중요한 부분이다.
한번 상속에 대해 알아보자.
상속이란 Class의 요소를 서로 공유할 수 있게 해주는 작업이다.
다만 아래에서 위로의 참조만 가능하다.
즉, 자식만이 부모의 요소에 접근이 가능한 것이다.
이유는 자바의 메모리 영역에서 배운 기초를 생각해 보면 설명이 가능하다.
그래도 설명해 보자면, 자식 Class에서는 extends 키워드를 통해 부모의 정보를 알고 있지만, 부모 Class에는 자식에 대한 정보가 없기 때문에, 참조값에 대한 정보가 없기 때문이다. ( 근데 참조값 넣어주면 될 수도 있지 않나란 궁금증이 생겼지만, 그건 상속관계보단 메모리 직접 참조이기 때문에 나중에 알아보자.)
상속의 역할은 여러 Class가 존재하고, 이 Class가 가진 요소들이 중복될 때 하나의 Class에서 이 공통 요소들을 한 번에 관리할 수 있게 해 준다.
이렇게 하면 코드 유지보수의 효율이 좋아지며 관리가 쉬워지며 중복되는 코드를 줄일 수 있다.
그렇다면 상속은 어떻게 하는 것일까?
class Parents {
}
부모 Class
class Child extends Parents{
}
자식 Class
자식 Class 명 뒤에 extends 키워드와 함께 상속받을 부모 Class의 이름을 입력하면 된다.
이렇게 부모, 자식 간의 관계를 정할 수 있게 되며 Child는 Parents의 요소에 접근할 수 있게 된다.
좋은 프로그래머는 프로그램의 메모리 관리 또한 신경 써야 한다.
새로운 Main 클래스에서 Child 객체를 생성하면 메모리 구조는 어떻게 될까 알아보자.
public class Main{
public static void main(String[] args) {
Child c = new Child();
}
}
객체가 생성되는 순간, 힙 영역에 Child와 Parents 부모 자식의 참조값이 들어가게 된다.
그렇다면 2개의 Class 주솟값이 힙 영역에 생성이 된 것이다.
그러면 우리는 생성된 객체의 요소에 접근할 때, 어디에서부터 접근을 하게 될까?
바로 Class 객체의 타입에서부터 시작된다.
위 코드에서는 Child로 객체의 타입을 생성하였으니 Child부터 서치를 진행하게 된다.
만약 Child의 모든 요소를 탐색하였지만 찾지 못하였으면 그때 부모 Class로 탐색을 진행하게 된다.
추가적으로 부모 또한 부모 Class를 상속받을 수 있다.
자식 <- 부모 1(자식) <- 조부모의 구조로 생각하면 된다.
이러한 경우에도 메모리 접근방식 개념은 기존에서 확장된다.
먼저 자식에서 찾고 없네? 부모로 가서 찾고 없네? 조부모로 가서 찾는다.
보통 조부모는 안 쓰이는데, 원활한 설명을 위해 채택하였다.(ㅋㅋ)
만약 최상위 부모까지 갔는데 찾는 요소가 없다면? 자바는 Complie Error를 뱉는다. (어차피 실행 안됨)
그리고 상속은 1개만 받을 수 있다. (추후 인터페이스에서 다중 구현을 허용해 해결할 수 있는데 지금은 스킵)
왜 1개만 상속을 받을 수 있게 해 놓았을까?
예시를 들어보자
print()라는 메서드를 Parents1과 Parents2 모두가 갖고 있다고 생각해 보자.
어떤 메서드를 사용할 건데..?
근본적인 문제에 부딪히게 된다.
컴퓨터는 이런 불확실한 상황을 최대한 배제시키는 것이 좋다.
따라서 자바는 이를 허용하지 않는다.
이 경우는 다이아몬드 문제라는 이름까지 있다.
오버라이딩에 대해 설명해 보자.
과거 오버라이딩에 정리해 놓은 적이 있다.
오버라이딩은 상속 관계에서 사용 가능한 메서드 재정의다.
즉 부모 Class의 메서드를 상속받은 자식 Class에서 재정의 하여 사용할 수 있게 해주는 기능이다.
하지만 이런 오버라이딩에도 규칙이 있다.
다시 알아보자
1. 메서드 이름이 같아야 한다.
2. 매개변수의 타입, 순서, 개수가 같아야 한다.
3. 반환타입이 같아야 한다.
4. 상위 메서드보다 오버라이드 된 메서드의 접근제한이 더 수용적이어야 한다.
5. 상위 메서드보다 더 많은 체크 예외를 throws 할 수 없다.
사실 기초원리를 생각해 보면 규칙은 모두 당연한 이야기를 하고 있는 거다.
1. 메서드 이름이 같아야 한다. -> 이름이 다르면 메서드 재정의가 아니라 그냥 신규 메서드다;;
2. 매개변수의 타입, 순서, 개수가 같아야 한다. -> 이게 다르면 그냥 오버로딩이다;
3. 반환타입이 같아야 한다. -> 자바에서는 반환타입이 다르면 메서드의 시그니처를 다르게 인식한다. (즉 오버로딩이며 2번과 같은 상황이다)
++
솔직히 여기까진 알았는데 4, 5번 이유를 생각하며 막혔다.
그래서 관련 정보를 좀 찾아보니 대충 다형성을 배워야 알 수 있는 개념인 것 같더라
그래서 나중에 수정하거나, 새 포스팅에서 다뤄야겠다 ㅎㅎ
++
4. 상위 메서드보다 오버라이드 된 메서드의 접근제한이 더 수용적이어야 한다. (
5. 상위 메서드보다 더 많은 체크 예외를 throws 할 수 없다.
쨋든 그렇다
Tip
오버라이드 배울 때, 오버라이딩을 할 메서드 바로 위에 어노테이션을 선언해 주면 자바가 이를 인식하고 자동으로 접근제한이나 참조등을 보고 컴파일 에러를 내준다.
오버라이드 할 때, 어노테이션 쓰자.
자바가 당신의 코딩을 도와준다.
어노테이션 사용법은 예시 코드로 한번 보고 끝내겠다.
@Override
protected void print() {
super.print();
System.out.println("- 저자 : " + author + ", isbn : " + isbn);
}
또 상속하면 빠질 수 없는 게 하나 있는데
바로 접근 제한자 중에 protected가 어렴풋이 기억난다.
이 접근제한자의 접근 제한 범위는 같은 package + 상속관계이다.
즉 package가 달라도 상속을 받은 자식이 있다면 부모의 protected 요소에 접근할 수 있다는 것이다.
기왕 하는 거 super까지 알아보자.
super가 뭘까?
바로바로 자식에서 부모의 요소에 접근하는 참조이다.
super() -> 부모의 생성자 접근
super.??? -> 부모의 요소/메서드 접근
아니 근데 그냥 자식에서 부모 객체 생성해서 접근하면 되는 거 아니야? 왜 super가 필요하지?라고 의문이 들 수 있다.
예시를 통해 설명해 보자.
일단 객체 생성하면 힙 영역이 차지가 된다. (라고 생각했는데 어차피 상속 관계면 애초에 힙 영역 차지되는데 아닌가 라는 의문증이 계속 든다 -> 객체 하나 더 만들면 또 차지하니까 메모리 낭비다. 바로 답 나와서 좋다)
또 자식 Class에서 오버라이드를 진행한 상태면..? 부모 Class와 변수 이름이 같다면..? 대충 생각해 봐도 굉장히 비효율 적이고 귀찮아진다.
아마 부모 Class 객체 생성을 통해 가능할 것 같은데 그러면 상속받은 이유가 없다... 내 뇌로는 이해가 안 된다.
그래서 super라는 키워드가 있다.
근데 super 쓴다고 무조건 접근할 수 있는 건 아니고, 만약 부모 Class의 변수나 메서드에 private 접근 제한자 붙어있으면 당연히 안된다. 공존하는 개념이다.
근데 우리 생성자도 배웠었다.
생성자는 Class객체가 생성되면 반드~시 먼저 자동으로 수행된다고 했었는데 부모를 가진 자식 객체를 생성하면 부모객체도 따라 생성되니까 생성자처리를 어떻게 해야 할지 조금은 궁금증이 생길 수 있다.
간단하게만 설명하겠다.
결론적으로 부모 생성자까지 실행시켜줘야 한다.
어떻게? super()를 통해
근데 super()를 안 써도 컴파일 오류가 안 날 수 있는데, 이건 부모 Class의 생성자가 기본 생성자일 때 오류가 안 난다.
이것도 과거에 배운 생성자 규칙을 정확히 잘 따른다.
기본 생성자 : 매개변수 없는 생성자
라고 생각하면 된다.
근데 부모 Class에서 매개변수 있는 생성자를 생성하는 순간, 자바가 기본 생성자 안 만들어 주니까 자식 Class에선 super() 함수를 통해 반드시 부모 Class의 생성자와 시그니처( 매개변수 타입, 순서, 개수)를 맞춰주어야 한다.
기본 생성자 없으면 자식 생성자에서 반~드시 super() 써야 한다.
아래 예시 코드 보고 자바 상속에 대해 알아보자.
물론 뭐든 눈으로 보고 이해하는 거보다 손으로 직접 타이핑하고 궁금증이 생기면 해결하는 게 가장 익힘이 빠르다.
가능하면 직접 써보고 손에 익혀가며 배우자.
코드
package example.extends1;
public class ShopMain {
public static void main(String[] args) {
Book b = new Book("JAVA", 10000, "Han", "12345");
Album a = new Album("앨범1", 15000, "seo");
Movie m = new Movie("영화1", 18000, "감독1", "배우1");
b.print();
a.print();
m.print();
int sum = b.getPrice() + a.getPrice() + m.getPrice();
System.out.println("상품 가격의 합 : " + sum);
}
} // main Class
package example.extends1;
public class Item {
private String name;
private int price;
Item(String name, int price){
this.name = name;
this.price = price;
}
protected void print() {
System.out.println("이름 : " + name + ", 가격 : " + price);
}
protected int getPrice(){
return price;
}
} // Item Class 부모
package example.extends1;
public class Book extends Item{
private String author ;
private String isbn ;
public Book(String name, int price, String author, String isbn) {
super(name, price);
this.author = author;
this.isbn = isbn;
}
@Override
protected void print() {
super.print();
System.out.println("- 저자 : " + author + ", isbn : " + isbn);
}
} // Book Class 자식
package example.extends1;
public class Album extends Item{
private String artist;
Album(String name, int price, String artist){
super(name, price);
this.artist = artist;
}
@Override
public void print(){
super.print();
System.out.println("- 아티스트 : " + artist);
}
} // Album Class 자식
package example.extends1;
public class Movie extends Item{
private String superVision;
private String actor;
Movie(String name, int price, String superVision, String actor) {
super(name, price);
this.superVision =superVision;
this.actor = actor;
}
@Override
public void print(){
super.print();
System.out.println("- 감독 : " + superVision + ", 배우 : " + actor);
}
} // Movie Class 자식
간단하게 Book, Album, Movie Class의 공통 요소인 이름, 가격, print(), getPrice() 요소들을 Item이라는 Class를 부모로 삼아 ShopMain에서 관리하게 만든 코드이다.
각 자식 Class에서는 생성자를 통해 Item Class의 생성자를 호출하며 객체들의 공통요소와 동시에 각 멤버 변수에 각 객체만의 정보 또한 저장한다.
그리고 Item의 print() 메서드를 오버라이드 하여 각 자식들만의 출력 Form 형태를 바꿔주고, Item getPrice() 메서드를 통해 등록된 물건의 총가격을 출력하는 코드이다.
예시에 잘 담아뒀으니 눈으로 보면서 이해해도 되지만, 직접 구현하는 것을 추천한다.
그래도 오늘 상속에 대해 개념을 정립하여 늦은 밤이지만 기분은 상쾌하다.
내일 다형성 할 건데, 이건 기억이 거의 안 나서 조금 두렵다.
그래도 설렌다.
'기술스택 > 자바(Spring)' 카테고리의 다른 글
자바 추상 클래스 (Abstract Class) (0) | 2025.02.11 |
---|---|
자바 다형성(Polymorphism) (2) | 2025.02.11 |
자바 final (1) | 2025.02.08 |
자바 static (1) | 2025.02.08 |
자바 메모리 구조 - 메서드, 스택, 힙 영역 (2) | 2025.02.08 |
- Total
- Today
- Yesterday
- 프로그래머스 상품을 구매한 회원 비율 구하기
- 김영한 실전 자바 기초
- 김영한
- 상품을 구매한 회원 비율 구하기 파이썬
- 스프링
- 백준
- 코딩테스트
- 상속
- 백준 피보나치 수열
- los 15단계
- zixem
- 코딩테스트 준비
- 기술스택
- webhacking.kr
- Los
- 자바
- 백준 피보나치
- static
- java
- 김영한 실전 자바 중급
- samron
- ys.k
- 김영한 실전 자바 기본
- lord of sql
- 프로그래머스
- extends
- los 15
- samron3
- 프로그래머스 상품을 구매한 회원 비율 구하기 파이썬
- spring
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |