상속
- 상속은 객체 지향 프로그래밍의 핵심 요소 중 하나
- 기존 클래스의 필드와 메소드를 새로운 클래스에서 재사용하게 해준다.
- 기존 클래스의 속성과 기능을 그대로 물려받는 것.
- 모든 자식 클래스에게 필요한 기능은 부모 클래스에만 추가하면 된다.
- 상속 관계 덕분에 공통 기능을 부모에서 관리하므로 중복을 줄일 수 있다.
- 상속을 사용하려면 extends 키워드를 사용하며 대상은 하나만 선택할 수 있다.
- 부모 클래스 (슈퍼 클래스) : 상속을 통해 자신의 필드와 메소드를 다른 클래스에 제공하는 클래스
- 자식 클래스 (서브 클래스) : 부모 클래스로부터 필드와 메소드를 상속받는 클래스
- 부모의 기능을 상속 받는다 = 부모의 기능을 확장한다 두 가지 표현으로 사용한다.
- 화살표 방향이 자식 -> 부모로 향하고 있다.
- 상속 받는 자식 클래스에서 extends 키워드를 사용해 부모 클래스를 표현하므로
ex) Child extends Parent == Child -> Parent와 같은 의미 - 부모 클래스에서는 자식 클래스를 모르지만 자식 클래스에서는 부모 클래스를 명시해놨기에 알 수 있다.
- 화살표는 "내가 상대방을 알고 있다"의 의미로 자식은 부모를 알고 있기 때문에 자식->부모 형태가 된다.
- 상속 받는 자식 클래스에서 extends 키워드를 사용해 부모 클래스를 표현하므로
- 자식 클래스는 부모 클래스의 기능을 물려받을 수 있다.
- 반대로 부모 클래스는 자식 클래스에 접근할 수 없다.
- 자바에서는 다중 상속을 지원하지 않는다.
- extends의 대상은 단 하나만 선택할 수 있다.
- 하나의 부모는 여러 자식이 있을 수 있지만 한 자식에게는 한 부모만 있을 수 있다.
- 위 예시처럼 다중 상속의 경우 자식이 move()를 호출할 경우 어느 부모의 move()를 사용해야 하는지 모호한 문제가 발생할 수 있다.
- 이런 문제를 다이아몬드 문제라고 한다.
- 또한 다중 상속 시 클래스 계층 구조가 매우 복잡해지기 때문에 자바에서는 다중 상속을 허용하지 않는다.
상속과 메모리 구조
//Car를 상속받는 ElectricCar 클래스가 있다고 가정
ElectricCar electricCar = new ElectricCar();
- 자식 클래스의 객체 생성 시 ElectricCar 뿐만 아니라 부모 클래스의 Car까지 함께 인스턴스를 생성한다.
- 참조 값은 하나지만 그 안에 두 가지 클래스 정보가 공존한다.
- 상속은 단순히 부모의 필드, 메소드만 상속받는 것이 아닌 부모 클래스의 인스턴스도 함께 포함해서 생성된다.
- 외부에서는 하나의 인스턴스를 생성하는 것처럼 보이지만 내부에서는 부모와 자식이 모두 생성되고 공간도 구분되어 있다.
- 즉, 상속 관계의 객체를 생성하면 그 내부에는 부모와 자식 인스턴스가 모두 생성된다.
- ★ ★ ★ ★ ★ 상속 관계인 경우에 메소드 호출시 어떻게 되는가? ★ ★ ★ ★ ★ ★
- 호출하는 변수의 타입(클래스)을 기준으로 선택한다.
- 만약 자식 클래스의 타입이면 먼저 자식 클래스에서 동일한 인스턴스 메소드가 있는지 확인 후 있다면 실행시키고 없다면 부모 클래스에서 찾아서 실행한다.
부모 클래스에도 없다면 더 상위 부모에서 찾으며 계속해서 없다면 컴파일 오류가 발생한다.
- 만약 자식 클래스의 타입이면 먼저 자식 클래스에서 동일한 인스턴스 메소드가 있는지 확인 후 있다면 실행시키고 없다면 부모 클래스에서 찾아서 실행한다.
- 상속 관계의 객체를 호출할 때, 대상 타입을 정하고 호출자의 타입을 통해 대상 타입을 찾는다.
- 현재 타입에서 기능을 찾지 못하면 상위 부모 타입에서 기능을 찾아서 실행한다.
- 호출하는 변수의 타입(클래스)을 기준으로 선택한다.
상속과 메소드 오버라이딩
- 부모에게 상속 받은 기능을 자식이 재정의하는 것을 메소드 오버라이딩(Overrding)이라고 한다.
- 부모 클래스의 메소드 명과는 같되, 다른 기능으로 재정의하는 것
- 메소드 오버라이딩 시 @Override를 메소드 선언부 위에 붙여준다.
- @Override는 상위 클래스의 메소드를 오버라이드하는 것을 알려주는 어노테이션이다.
- 어노테이션 : 주석과 비슷하며 프로그램이 읽을 수 있는 특별한 주석과 같다.
- @Override 어노테이션은 생략이 가능하지만 써주는 것이 좋다.
- 부모 클래스의 메소드를 오버라이드하는 것을 컴파일러에게 알려줌으로 오버라이딩 조건을 만족시키지 않으면 오류를 통해 알려주기에 실수를 방지할 수 있다.
- @Override는 상위 클래스의 메소드를 오버라이드하는 것을 알려주는 어노테이션이다.
- 메소드 오버로딩 vs 메소드 오버라이딩
- 메소드 오버로딩(과적): 메소드 이름이 같고 매개변수가 다른 메소드를 여러개 정의하는 것.
- 메소드 오버라이딩(재정의): 하위 클래스에서 상위 클래스의 메소드를 재정의하는 것.
- 메소드 오버라이딩의 조건
- 메소드 명: 메소드 이름이 같아야 한다.
- 메소드 매개 변수: 메소드 매개 변수의 타입, 순서, 개수가 같아야 한다.
- 리턴 타입: 리턴 타입이 같아야 한다.
- 접근 제어자: 상위 클래스의 메소드보다 더 제한적인 접근제어자를 사용해서는 안된다.
ex) 상위 클래스 protected -> 하위 클래스 protected, public만 가능하다. - 예외: 상위 클래스의 메소드보다 더 많은 체크 예외를 throws로 선언할 수 없다.
- static, final, private 키워드가 붙은 메소드는 오버라이딩 할 수 없다.
- static 메소드는 클래스 레벨에서 작동하므로 인스턴스 레벨에서 사용하는 오버라이딩이 의미가 없다.
- final 메소드는 재정의를 금지한다.
- private 메소드는 해당 클래스에서만 접근 가능하므로 하위 클래스에서 보이지 않아서 오버라이딩 할 수 없다.
- 생성자: 생성자는 오버라이딩 할 수 없다.
- 상속 관계에서는 부모 클래스의 public, protected로 선언된 변수, 메소드만 호출할 수 있다.
super
- 부모와 자식의 필드명이 같거나 오버라이딩되어 있으면 자식에서 부모의 필드나 메소드를 호출할 수 없다.
- 이때 super 키워드를 사용하면 부모를 참조할 수 있다.
public class Child extends Parent {
public String value = "child";
@Override
public void hello() {
System.out.println("Child.hello");
}
public void call() {
System.out.println("this.value = " + this.value); //this 생략 가능
System.out.println("super.value = " + super.value);
this.hello();
super.hello();
}
}
- this는 자기 자신의 참조를 의미하며 생략할 수 있다.
- this가 생략됐다면 먼저 자신의 클래스에서 찾아보고 없으면 상위 클래스에서 찾는다.
- super는 부모 클래스에 대한 참조를 의미한다.
- 필드 이름과 메소드 이름이 같아도 super를 사용해 부모 클래스의 필드와 메소드를 사용할 수 있다.
- 상속 관계의 인스턴스를 생성하면 부모 클래스와 자식 클래스의 인스턴스가 각각 다 생성된다.
- 즉, 각각의 생성자도 모두 호출되어야 한다.
- 자식 클래스의 생성자에서 부모 클래스의 생성자를 반드시 호출해야 한다.
- 상속 관계에서 부모 클래스의 생성자를 호출할 때는 super(...)를 사용한다.
- 부모 클래스의 기본 생성자를 호출할 경우 super()는 생략할 수 있다.
- super(...) 생략시 자동으로 기본 생성자 super()를 만들어준다.
- 매개 변수가 있는 생성자를 호출하는 경우 직접 작성해줘야 한다.
- 부모 클래스의 기본 생성자를 호출할 경우 super()는 생략할 수 있다.
class Child extends Parent{
public Child() {
this("hi");
}
public Child(String name) {
super();
}
}
- super(...)는 자식 생성자 안에서 반드시 첫 줄에 호출해야한다.
- this(...)와 super(...)는 둘 다 첫 줄에 명시해야 하므로 함께 사용할 수 없다.
하지만 위 예시와 같이 사용할 수 있으며 this(...)를 사용하더라도 마지막에는 반드시 super(...)를 첫 줄에 호출해야한다.
- this(...)와 super(...)는 둘 다 첫 줄에 명시해야 하므로 함께 사용할 수 없다.
- 상속 관계에서 생성자 호출은 부모에서 자식 순서로 실행된다.
- 생성자로 초기화 시 부모의 데이터를 먼저 초기화하고 자식의 데이터를 초기화한다.
- final 클래스
- final로 정의된 클래스를 다른 클래스에서 상속받을 수 없다.
출처:[인프런 김영한 실전 자바 - 기본편]
김영한의 실전 자바 - 기본편 강의 | 김영한 - 인프런
김영한 | 실무에 필요한 자바 객체 지향의 핵심 개념을 예제 코드를 통해 쉽게 학습합니다., 국내 개발 분야 누적 수강생 1위, 제대로 만든 김영한의 실전 자바[사진][임베딩 영상]단순히 자바 문
www.inflearn.com
'Java > [인프런 김영한 실전 자바 - 기본편]' 카테고리의 다른 글
[인프런 김영한 실전 자바 - 기본편] 다형성2 (1) | 2024.07.17 |
---|---|
[인프런 김영한 실전 자바 - 기본편] 다형성1 (0) | 2024.07.16 |
[인프런 김영한 실전 자바 - 기본편] final (0) | 2024.07.16 |
[인프런 김영한 실전 자바 - 기본편] 자바 메모리 구조와 static (0) | 2024.07.16 |
[인프런 김영한 실전 자바 - 기본편] 접근 제어자 (0) | 2024.07.16 |