상속은 이미 잘 개발된 클래스를 재사용해서 새로운 클래스를 만들기 때문에 중복되는 코드를 줄여준다.
예를 들어 field1, field2, method1(), method2()를 가지는 클래스를 작성한다고 가정을 해봤을 때 filed1과 method1()을 가지고 있는 클래스가 있다면, 4개를 모두 처음부터 작성하는 것보다는 클래스를 상속하고, filed2 와 method2()만 추가 작성하는 곳이 보다 효울적이고 개발 시간을 절약해준다.
상속을 이용하면 부모 클래스의 수정으로 모든 자식 클래스들도 수정되는 효과를 가져오기 때문에 유지 보수 시간을 최소화 할 수 있다.
클래스 상속
현실에서 상속은 부모가 자식을 선택해서 물려주지만, 프로그램에서는 자식이 부모를 선택한다. 자식 클래스를 선언할 때 어떤 부모 클래스를 상속받을 것인지 결정하고, 선택된 부모 클래스는 아래와 같이 extends 뒤에 기술한다.
class 자식 클래스 extends 부모 클래스{
...
}
예를 들어 Car 클래스를 상속해서 SportsCar 클래스를 설계하려면 아래와 같이 작성하면 된다.
class SportsCar extends Car{
...
}
자바에서 상속은 다음과 같은 특징을 가지고 있다.
1. 여러 개의 부모클래스를 상속할 수 없다. 그러므로 아래와 같이 extends 뒤에는 단 하나의 부모 클래스만 와야 한다.
class 자식클래스 extends 부모클래스1, 부모클래스2{
...
}
// 위는 부모클래스를 2개 지정했기 때문에 에러가 발생한다.
// 따라서 아래처럼 작성해야 에러가 발생하지 않는다.
class 자식클래스 extends 부모클래스1{
...
}
2. 부모 클래스에서 private 접근 제한을 갖는 필드와 메소드는 상속 대상에서 제외된다. 그리고 부모 클래스와 자식 클래스가 다른 패키지에 존재한다면 default 접근 제한을 갖는 필드와 메소드도 상속 대상에서 제외된다.
부모 생성자 호출
현실에서 부모 없는 자식이 있을 수 없듯이 자바에서도 자식 객체를 생성하면, 부모 객체가 먼저 생성되고 그 다음 자식 객체가 생성된다.
모든 객체는 클래스의 생성자를 호출해야지만 생성된다. 부모 객체도 예외는 아니다. 따라서 만약 자식 객체의 클래스에 생성자를 작성하지 않으면 부모 객체를 먼저 생성하는 생성자가 자동 생성된다.
예를 들어 SportsCar 의 생성자가 명시적으로 선언되지 않았다면 컴파일러는 아래와 같은 기본 생성자를 생성한다.
class SportsCar extends Car{
public SportsCar(){
super();
}
}
첫 줄에 super(); 가 추가된 것을 볼 수 있는데 super()는 부모의 기본 생성자를 호출한다. 즉 Car 클래스의 아래 생성자를 호출한다. Car.java 소스 코드에서도 Car의 생성자가 선언되지 않았지만 컴파일러에 의해 기본생성자가 만들어지므로 문제없이 실행된다.
public Car(){
}
만약 직접 자식 생성자를 선언하고 명시적으로 부모 생성자를 호출하고 싶다면 아래와 같이 작성하면 된다.
자식클래스(매개변수선언, ...){
super(매개값, ...);
}
super(매개값, ...)는 매개값의 타입과 일치하는 부모 생성자를 호출한다. 만약 매개값의 타입과 일치하는 부모 생성자가 없을 경우 컴파일 에러가 발생한다.
super(매개값, ...)가 생략되면 컴파일러에 의해 super() 가 자동적으로 추가되기 때문에 부모의 기본 생성자가 존재해야 한다. 부모 클래스에 기본 생성자가 없고 매개 변수가 있는 생성자만 있다면 자식 생성자에서 반드시 부모 생성자의 호출을 위해 super(매개값, ...)를 명시적으로 호출해야 한다. super(매개값, ...)는 반드시 자식 생성자 첫 줄에 위치해야 하며, 그렇지 않으면 컴파일 에러가 발생한다.
메소드 재정의
부모 클래스의 모든 메소드가 자식 클래스에 맞게 설계되어 있다면 가장 이상적인 상속이지만, 어떤 메소드는 자식 클래스가 사용하기에 적합하지 않을 수 있다. 이 경우 상속된 일부 메소드는 자식 클래스에서 다시 수정해서 사용해야 한다. 자바는 이런 경우를 위해 메소드 재정의(오버라이딩 : overriding) 기능을 제공한다.
메소드 재정의 방법
메소드 재정의는 자식 클래스에서 부모 클래스의 메소드를 다시 정의하는 것을 말한다. 메소드를 재정의할 때에는 다음과 같은 규칙에 주의해서 작성해야 한다.
- 부모의 메소드와 동일한 시그니처(리턴 타입, 메소드 이름, 매개 변수 목록)를 가져야 한다.
- 접근 제한을 더 강하게 재정의 할 수 없다.
- 재로운 예외(Exception)를 throws 할 수 없다.
매소드가 재정의되었다면 부모 객체의 메소드는 숨겨지기 때문에, 자식 객체에서 메소드를 호출하면 재정의된 자식 메소드가 호출 된다.
부모 메소드 호출
자식 클래스에서 부모 메소드를 재정의하게 되면, 부모 클래스의 메소드는 숨겨지고 재정의된 자식 메소드만 사용된다. 그러나 자식 클래스 내부에서 재정의된 부모 클래스의 메소들르 호출해야 하는 상황이 발생한다면 명시적으로 super 키워드를 붙여 부모 메소드를 호출할 수 있다.
super.부모메소드();
final 클래스와 final 메소드
final 키워드는 클래스, 필드, 메소드를 선언할 때 사용할 수 있는데, 해당 선언이 최종 상태이고 결코 수정될 수 없음을 뜻한다. final 키워드는 클래스, 필드, 메소드 선언에 사용될 경우 해석이 조금 달라지는데 필드를 선언할 때 final이 지정되면 초기값 설정 후 더 이상 값을 변경할 수 없다.
클래스와 메소드를 선언할 때 final 키워드가 지정되면 상속과 관련이 있다는 의미이다.
상속할 수 없는 final 클래스
클래스를 선언할 때 final 키워드를 class 앞에 붙이면 이 클래스는 최종적인 클래스이므로 상속할 수 없는 클래스가 된다. 즉, final 클래스는 부모 클래스가 될 수 없어 자식 클래스를 만들 수 없다는 것이다.
재정의 할 수 없는 final 메소드
메소드가 선언될 때 final 키워드를 붙이면 이 메소드는 최종적인 메소드이므로 재정의할 수 없는 메소드가 된다. 즉, 부모 클래스를 상속해서 자식 클래스를 선언할 때 부모 클래스에 선언된 final 메소드는 자식 클래스에서 재정의 할 수 없다는 것이다.
'Java' 카테고리의 다른 글
| 자바 추상 클래스 (0) | 2023.06.27 |
|---|---|
| 자바 클래스 타입 변환과 다형성 (0) | 2023.06.26 |
| 자바 패키지와 접근 제한자 (0) | 2023.06.26 |
| 자바 인스턴스 멤버와 정적 멤버 (0) | 2023.06.23 |
| 자바 메소드 (0) | 2023.06.23 |