[Java] 상속과 오버라이딩

자바는 클래스의 상속을 지원한다.

만약 B 클래스가 A 클래스를 상속받는다면, B는 A의 모든 것을 사용할 수 있으며, A로 취급될 수도 있다.
이럴 경우 B를 서브클래스(자식클래스), A를 슈퍼클래스(부모클래스)라고 부른다.

상속은 extends 키워드로 정의된다.
부모를 확장해서 선언한다는 뜻이다.
클래스는 무조건 딱 하나만 상속받을 수 있다.
class 자식 extends 부모
{ ... }

자식은 부모의 public, protected 필드&메소드를 그대로 물려받는다.
아래 코드는 자식 객체에서 부모의 메소드를 사용하는 짤막한 예시다. image

image

그리고, 자식 클래스의 객체는 부모 타입으로 치환 가능하다. 이런걸 OOP 용어로 리스코프 치환이라 부르는데...
여튼 그렇다.
어차피 자식은 부모의 인터페이스를 그대로 가지니, 부모로 바꿔도 거의 동일한 동작을 보장할 수 있을 거란 기대가 있기 때문이다. image

image B 객체가 A 타입의 변수에 저장됐지만,
동작은 동일하다.

그리고 오버라이딩이란 게 있다. 중요하다.


오버라이딩
오버라이딩은 자식 클래스에서 부모의 메소드를 재정의하는 것이다. 양쪽 메소드의 시그너처는 같아야 한다.

메소드를 오버라이딩하는 것으로, 상속관계에 있는 다른 타입의 객체가 각각 다른 행동을 하게 할 수 있다.
이걸 동적 다형성이라 한다.

뭔 말이냐 하면. 코드를 보자 image

image 자바에서 메소드의 호출을 변수의 타입만으로 결정한다면, 위의 두 메소드 호출 결과는 전부 "이건 A 객체요"여야 한다.

하지만 그렇지 않다.
자바에서 오버라이딩을 수행하면.
재정의된 메서드들을 가상함수테이블에 넣고 변수의 타입이 아닌, 실제 객체의 타입을 추적해서 메소드를 선택. 호출하게 하기 때문이다.

때문에 같은 A 타입의 변수라도, 그 안에 들어있는 건 A를 상속받은 B일 수도 C일 수도 있다.
같은 A의 메소드 호출이라도 실제 메소드는 B나 C의 재정의일 수도 있다.
이게 객체지향의 가장 핵심적인 원리다.
이런 것에 대한 자세한 응용은 디자인 패턴 등을 통해 학습하는 것이 좋다.


어노테이션 Override
이건 오버라이딩이 제대로 됐는지 검사해준다.
딱히 뭐 기능이 추가되는건 아니다. image

image

대신 잘못된 오버라이딩 시도를 바로잡아준다. image

image 코드도 좀더 명확해지는 편이다.
웬만하면 붙여주는 게 좋다.


상속 금지 final
클래스 앞에 final을 붙이면 상속이 불가능한 클래스가 된다.
final 클래스에 대한 상속 시도는 에러를 던진다. image

image

이건 메소드에도 붙일 수 있다.
그러면 그 메소드는 오버라이딩이 금지된다. image

image


super 키워드
super는 부모 객체를 가리키는 키워드다.
this와 거의 동일한 방식으로 사용할 수 있다.

가장 자주 쓰이는건 부모 생성자를 불러서 초기화를 행할 때다. image

image

당연히 부모 클래스의 필드를 직접 접근할 때도 사용할 수 있다. image

image

특히 오버라이딩한 메소드에서 부모 메소드를 호출할 때. image

image 저기서 super를 사용하지 않으면 메소드 자신을 불러서 무한재귀에 빠지게 된다"