상속
상속은 상위 클래스의 필드와 메소드를 하위 클래스에게 물려주는 것이다. 상위 클래스는 하위 클래스보다 더 추상적이며 공통적인 성질을 가지고있으며, 이를 하위 클래스가 물려받아 구체화하는 식으로 코드를 작성하기 위해 상속을 이용한다.
상속은 주는 장점은 다음 세 가지가 있다.
- 클래스의 간결화: 멤버의 중복 작성 불필요
- 클래스 관리 용이: 클래스의 계층적 분류
- 소프트웨어 생산성 향상: 클래스 재사용과 확장 용이
I. 상속 선언과 객체 생성
extends 키워드를 이용해 상속받는 자식 클레스를 선언할 수 있다.
그리고 서브 클래스인 Student로 만든 객체에서는 자신의 멤버인 stdnum은 물론 불려받은 name 멤버까지 사용할 수 있다.
또한 서브 클래스 안에서도 슈퍼 클래스의 멤버를 마치 자신의 멤버처럼 this 키워드로 접근할 수 있다.
자바 상속의 특징
자바에서 상속은 다음과 같은 특징을 가진다.
- 다중 상속을 지원하지 않음. extends 다음에는 클래스 이름이 하나만 올 수 있음.
- 상속의 횟수에 제한이 없음.
- 자바에서는 계층 구조의 최상위에 java.lang.Object 클래스가 있음.
상속과 생성자
슈퍼 클래스도, 서브 클래스도 모두 각각의 생성자를 가지고 있다. 서브 클래스 객체가 생성될 때는 이 모든 생성자들이 순서대로 호출된다.
graph TD C -->|B 생성자 호출| B B -->|A 생성자 호출| A A --> B B --> C
서브 클래스 객체 생성 시 슈퍼 클래스에 여러 생성자가 있는 경우, 원칙적으로는 슈퍼 클래스의 어떤 생성자를 함께 호출할지 명시적으로 지정해야 한다. 이 때 슈퍼클래스 생성자인 super()를 이용한다.
super()로 슈퍼 클래스의 생성자를 지정하지 않으면 기본 생성자가 호출된다.
II. 캐스팅
캐스팅은 타입 변환을 말한다. 자바에서 클래스에 대한 캐스팅은 업캐스팅과 다운캐스팅으로 나뉜다.
업캐스팅
서브 클래스 객체에 대한 레퍼런스를 슈퍼 클래스 타입으로 변환하는 것. 위로 거슬러 올라가는 형태다.
압케스팅한 레퍼런스로는 서브 클래스의 멤버에 접근하지 못하고 슈퍼 클래스의 멤버에만 접근할 수 있다.
또한 업캐스팅은 p = (Person)s와 같이 명시적인 캐스팅이 필요하지 않다.
다운캐스팅
다운캐스팅은 업캐스팅의 반대로, 슈퍼 클래스 객체에 대한 레퍼런스를 서브 클래스 타입으로 바꾸는 것이다.
다운캐스팅은 명시적 캐스팅이 필요하다.
instanceof
instanceof 연산자는 업캐스팅된 객체가 실제로 어느 서브 클래스이 객체인지 알기 위해 사용하는 연산자이다.
다음과 같은 클래스들이 있다고 해보자.
p1과 p2는 실제로 Person 클래스의 객체인지, 아니면 이를 상속받은 Student나 Teacher 클래스의 객체인지, 코드만 보고는 구분이 어렵다. 그래서 다음과 같이 instanceof 연산자를 사용하면 이렇게 어떤 서브 클래스로부터 업캐스팅된것인지 알 수 있다.
III. 오버라이딩
오버라이딩은 슈퍼 클래스에 이미 작성된 메소드를, 그를 상속한 서브 클래스에서 재작성하는 것이다. 슈퍼 클래스에 존재하는 기능과 같은 맥락의 기능임을 명시하되, 작업 내용은 달리 해야할 때 오버라이딩을 한다.
즉 오버라이딩은 슈퍼 클래스의 원본 함수를 서브 클래스에서 덮어쓰는 것으로 볼 수 있다.
오버라이딩 함수 위에 붙이는 @Override 어노테이션은 필수는 아니지만, 있으면 컴파일러가 오버라이딩 함수임을 알 수 있어 오타와 같은 문법 오류를 미리 잡아주기도 하며, 코드에 대한 직관성도 높이므로 실무에서는 항상 사용된다.
동적 바인딩
위 코드에서, Rect나 Circle로 레퍼런스 변수를 생성하지 않고 Shape로 생성한 뒤 업캐스팅하면 어떻게 될까?
결과는 같다. Rect나 Circle 객체를 Shape 타입의 레퍼런스로 가리키더라고 draw() 메소드 호출 시 오버라이딩 된 내용이 존재하면 그 서브 클래스의 draw()를 호출한다. 이것을 동적 바인딩이라고 부른다. 동적 바인딩은 어떤 메소드를 실행할 지 컴파일시에 정해지징 않고 런타임 시에 정해진다.
하지만 서브 클래스에서 오버라이딩된 메소드를 실행하지 않고 꼭 슈퍼 클래스의 원본 메소드를 실행해야 하는 경우가 있다면 super를 이용할 수 있다.
- this.객체내멤버
- super.객체내슈퍼클래스멤버
오버리이딩 특징
- 오버라이딩은 다형성 실현에 목적을 둔다.
- 슈퍼 클래스와 동일한 형태로 선언한다. 내용만 날라야 한다.
- 슈퍼 클래스의 접근 지정자보다 접근 범위를 좁일 수 없다.
static,private,final로 선언된 메소드는 오버라이딩이 불가능하다.
IV. 추상화
추상 메소드는 코드가 구현되어있지 않고 선언만 있는 껍데기에 불과한 메소드를 말하며, 이런 추상 메소드를 포함하는 클래스를 추상 클래스라고 한다.
추상 메소드를 선언할 땐 abstract키워드와 함께 쓴다.
추상 클래스
추상 메서드를 포함하는 클래스는 추상 클래스여야 한다. 이때 클래스 역시 abstract 키워드와 함께 쓰인다.
추상 클래스의 특징
- 추상 클래스는 객체를 생성할 수 없다. 추상 클래스는 그 자체로 객체를 생성하려고 만드는 클래스가 아니라, 그것을 상속한 서브 클래스에서 추상 메소드를 오버라이딩하여 사용하기 위해 만든다.
- 추상 클래스는 서브 클래스가 어떤 기능을 구현해야 하는지 명료하게 알려주는 설계도와 같은 역할을 한다. 이는 다형성 실현에 기여한다.
- 설계와 구현을 분리할 수 있다. 추상 클래스를 통해 개발의 방향을 미리 잡아놓고 서브 클래스를 만들어나는 체계적인 구현 작업을 할 수 있다.
V. 인터페이스
인터페이스는 추상 클래스보다 더 상위 단계로, 클래스가 구현해야 할 기능 명세서와 같다. 인터페이스는 다음 요소들로 구성할 수 았다.
- 상수:
public static final로 고정 - 추상 메서드:
public abstract로 고정 default메서드:public default로 고정private메서드: 인터페이스 내에서만 호출 가능static메서드: 접근 지정자 생략 시public, 또는private으로 지정 가능
인터페이스의 필드는 오로지 상수만 올 수 있으며, default, private, static 메서드는 반드시 코드가 구현되어 있어야 한다. 또한 인터페이스에 선언된 추상 메서드는 이를 구현받는 클래스에서 반드시 오버라이딩을 해야 한다.
인터페이스 특징
- 인터페이스의 필드는 오로지 상수만 올 수 있다.
default,private,static메서드는 반드시 코드가 구현되어 있어야 한다.- 인터페이스에 선언된 추상 메서드는 이를 구현받는 클래스에서 반드시 오버라이딩을 해야 한다.
- 인터페이스는 객체를 생성할 수 없다. 하지만 레퍼런스 변수는 선언이 가능하다.(추상 클래스와 동일)
- 인터페이스끼리 상속된다. 추상 클래스와 달리 다중 상속이 가능하다.
인터페이스 구현
인터페이스를 클래스가 이어받아 사용하는것을 인터페이스 구현이라고 부른다. 아래는 인터페이스 구현 예제이다.
인터페이스 상속
인터페이스끼리도 상속이 가능하며, 추상 클래스와 다르게 다중 상속도 가능하다.
다중 인터페이스
클래스에는 인터페이스를 여러 개 구현할 수 있다.
- 추상 메소드:
public abstract생략 가능 ->void playMusic(); - 상수 필드:
public static final생략 가능 ->int powerwatt; default메소드:public생략 가능 ->default void powerOff();
이미지에 있는 추상 클래스와 인터페이스의 비교 표를 마크다운 형식으로 정리해 드립니다.
추상 클래스 vs 인터페이스 비교
| 비교 | 목적 | 구성 |
|---|---|---|
| 추상 클래스 | 추상 클래스는 서브 클래스에서 필요로 하는 대부분의 기능을 구현하여 두고 서브 클래스가 상속받아 활용할 수 있도록 하되, 서브 클래스에서 구현할 수밖에 없는 기능만을 추상 메소드로 선언하여, 서브 클래스에서 구현하도록 하는 목적(다형성) | 추상 메소드와 일반 메소드 모두 포함. 상수, 변수 필드 모두 포함 |
| 인터페이스 | 인터페이스는 객체의 기능을 모두 공개한 표준화 문서와 같은 것으로, 개발자에게 인터페이스를 상속받는 클래스의 목적에 따라 인터페이스의 모든 추상 메소드를 만들도록 하는 목적(다형성) | 변수 필드(멤버 변수)는 포함하지 않음. 상수, 추상 메소드, 일반 메소드, default 메소드, static 메소드 모두 포함. protected 접근 지정 선언 불가. 다중 상속 지원 |