1. 상속 : 기존 클래스의 필드와 메서드를 새로운 클래스에서 물려받는 것. (extends 키워드를 이용)
◆ 부모클래스 : 새로운 클래스에 필드와 메서드를 물려주는(상속해주는) 클래스 = 상위 클래스
◆ 자식클래스 : 부모클래스가 상속을 해주는 클래스 = 하위 클래스
- 자식 클래스는 부모 클래스의 기능을 상속받아 사용할 수 있지만 부모 클래스는 자식클래스에 접근할 수 없다.
- 자바는 다중 상속을 지원하지 않아 부모 클래스는 하나만 가질 수 있다. 물론 부모 클래스도 부모를 가질 순 있다.
2. 상속과 메모리 구조
- 부모 클래스로부터 상속을 받아 새로운 객체를 생성하면 상속 관계에 있는 부모 클래스까지 함께 포함해 인스턴스를 생성한다.
즉, 참조값은 하나지만 실제로 그 안에는 두 가지 클래스 정보가 공존하게 된다. 외부에서 볼 때는 하나의 인스턴스를 생성하는 것 같지만 내부에서는 부모와 자식이 모두 생성되고 공간도 구분된다.
이해를 쉽게 하기 위해 내가 좋아하는 베이스로 비유해봤다...
부모클래스 Instrument 는 악기이다. 악기는 연주하기, 이름 등등의 모든 악기들이 가지는 공통적인 속성과 기능들을 갖고있다.
자식클래스 Bass 는 이름이 베이스이고, 슬랩이라는 기능을 가지고 있다. 자식 클래스는 부모 클래스의 특징을 물려받고, 거기에 자신만의 고유한 특징을 더한다고 보면 된다.
bass.slap() 을 호출하면 참조값을 확인해 호출하게 되는데 호출하는 변수의 타입(클래스)를 기준으로 선택한다. bass는 자식 클래스이기 때문에 slap() 을 찾기 위해 우선 Bass 클래스를 먼저 가게된다. 만약 slap() 이 아니라 bass.play()를 호출하게 되면 자신의 타입에 없기 때문에 부모 클래스인 Instrument로 가서 play() 메서드를 찾게된다.
즉, 현재 타입에서 기능을 찾지 못하면 상위 부모 타입으로 기능을 찾아 실행한다. 부모 클래스까지 갔는데도 기능을 찾지 못하면 컴파일 오류가 발생한다.
< 순서 >
1. 호출한 메서드의 참조값을 확인한다.
2. 자신의 타입에 해당하는 클래스에서 먼저 기능을 찾는다.
3. 찾는 기능이 없을 시 상위 부모 클래스로 가서 기능을 찾게된다.
4. 그럼에도 기능을 못찾으면 컴파일 오류가 난다.
3. 메서드 오버라이딩 : 상속받은 기능을 재정의 하는 것 ( @Override )
class Bass extends Instrument {
@Override
public void play() {
System.out.println("베이스를 빠르게 연주합니다."); // 부모의 기능을 재정의
}
public void slap() {
System.out.println("슬랩 기술을 사용합니다.")
}
}
→ 이렇게 오버라이딩 하는 경우 메모리 구조에서는 이미 자식 타입에서 해당 기능이 있기 때문에 부모 타입으로 가 기능을 찾을 일이 없다.
< 오버라이딩 시 주의할 점 >
- 메서드 이름이 같아야 한다.
- 메서드 매개변수(파라미터) 타입, 순서, 개수가 같아야 한다.
- 반환 타입이 같아야 한다. ( 단, 반환 타입이 하위 클래스 타입일 수 있다. )
- 오버라이딩 메서드의 접근 제어자는 상위 클래스의 메서드보다 더 제한적일 순 없다. (부모는 public인데 자식이 private이면 안됨)
- 오버라이딩 메서드는 상위 클래스의 메서드보다 더 많은 체크 예외를 throws로 선언할 수 없다. (더 적거나 같은 수의 예외, 또는 하위 타입의 예외 선언은 ok)
- 생성자는 오버라이딩 할 수 없다.
- 상속 관계를 사용하면 자식 클래스의 생성자에서 부모 클래스의 생성자를 반드시 호출해야 한다. ( super ... )
- static, final, private 키워드가 붙은 메서드는 오버라이딩 될 수 없다.
-> static은 클래스 레벨에서 작동하므로 인스턴스 레벨에서 사용하는 오버라이딩이 의미가 없다. 그냥 클래스 이름을 통해 필요한 곳에 직접 접근하면 된다.
-> final 메서드는 재정의를 금지한다.
-> private 메서드는 해당 클래스에서만 접근을 허용한다. 하위 클래스에서는 사용할 수 없다.
4. 다형성 : 다양한 형태, 여러 형태를 참조할 수 있다고 해서 다형적 참조라고 한다.
- 보통 하나의 객체는 하나의 타입으로 고정되어 있는데 다형성을 이용하면 하나의 객체가 다른 여러 타입으로 취급될 수 있다.
package poly.basic;
public class PolyMain {
public static void main(String[] args) {
//부모 변수가 부모 인스턴스 참조
System.out.println("Parent -> Parent");
Parent parent = new Parent();
parent.parentMethod();
// parent.childMethod(); 부모는 자식의 기능을 참조할 수 없다.
//자식 변수가 자식 인스턴스 참조
System.out.println("Child -> Child");
Child child = new Child(); // Child 인스턴스 생성 메모리 상 Child 와 Parent가 모두 생성된다. 생성된 참조값을 Child 타입의 변수인 child에 담아둔다.
child.parentMethod();
child.childMethod(); //호출 시 인스턴스의 Child 클래스에 있는 childMethod() 가 호출된다.
//부모 변수가 자식 인스턴스 참조(다형적 참조)
System.out.println("Parent -> Child");
Parent poly = new Child(); // 부모 타입은 자식 타입을 담을 수 있다.
poly.parentMethod(); //
//Child child1 = new Parent(); //자식은 부모를 담을 수 없다.
//자식의 기능은 호출할 수 없다. 컴파일 오류 발생
//poly.childMethod();
}
}
- 부모 타입은 자식 타입을 담을 수 있고, 그 밑으로 더 하위 클래스가 있다면 그들 모두를 담을 수 있다. 하지만 자식 타입은 부모 타입을 담을 수 없다.
- Parent poly = new Child(); 를 실행하면 먼저 참조값을 통해 인스턴스를 찾는다. 다음으로 인스턴스 안에서 실행할 타입을 찾는데 poly 는 Parent 타입이기 때문에 Parent 클래스부터 필요한 기능을 찾는다. 상속 관계는 부모 방향으로 찾아 올라갈 수 있지만 자식 방향으로 내려올 순 없다. ( 즉, 찾고 있는 childMethod()를 찾을 수 없어 컴파일 오류가 발생 )
5. 캐스팅
package poly.basic;
public class CastingMain2 {
public static void main(String[] args) {
//부모 변수가 자식 인스턴스 참조(다형적 참조)
Clothes clothes = new Hoodies(); //x001
//단 자식의 기능은 호출할 수 없다. 컴파일 오류 발생
//clothes.hoodiesMethod();
//일시적 다운캐스팅 - 해당 메서드를 호출하는 순간만 다운캐스팅
((Hoodies) clothes).hoodiesMethod(); // 연산자 우선순위 상 .이후가 먼저이다. 따라서 괄호로 감싸면 먼저 연산된다.
}
}
//
// Hoodies hoodies = (Hoodies) clothes;
// ((Hoodies) clothes).hoodiesMethod(); -> 이렇게 사용하는 것이 더 효율적이다. 위의 예시는 다운캐스팅을 이해하기 위한 예제로 너무 깊게 빠지지 말 것
1) 다운캐스팅 : 부모 타입 → 자식 타입
- 다운 캐스팅을 하고자 하는 대상의 앞에 괄호를 입력하고, 괄호 안에 타입을 지정하면 참조 대상을 특정 타입으로 잠시 변경할 수 있다.
- 캐스팅을 한다고 해서 Clothes clothes의 타입이 변하는 것은 아니다. 부모 타입을 자식 타입으로 다운캐스팅 한 후에 참조값을 꺼내고 꺼낸 참조값이 Hoodies 타입이 되는 것이다. 따라서 clothes의 타입은 Clothes 그대로 유지된다.
2) 업캐스팅 : 자식 타입 → 부모 타입
Opinion
다운캐스팅을 공부하는데 너무 어려워서 강의를 세 번 정도 되돌아봤다. 그래도 확신이 안서서 다른 분들한테도 질문을 했는데도 아직 확실하게 모르겠다.. 하지만 뒤에 내용을 공부하다 보면 알아서 알게될 것이라고 다들 그러셔서 일단은 내가 지금 이해한 대로만 생각하고 더 깊게 생각하지 말자!
'내일배움캠프 > TIL' 카테고리의 다른 글
[Spring_4기 본캠프] Spring 입문 - 백엔드 개발 | Day 31 (1) | 2024.11.29 |
---|---|
[Spring_4기 본캠프] Spring 입문 - build terminal 오류 트러블 슈팅 | Day 30 (3) | 2024.11.28 |
[Spring_4기 본캠프] 자바 메모리 구조와 static | Day 28 (0) | 2024.11.26 |
[Spring_4기 본캠프] 키오스크 과제&트러블 슈팅 | Day 27 (0) | 2024.11.25 |
[Spring_4기 본캠프] 기본형과 참조형, final | Day 26 (0) | 2024.11.22 |