목차
- 상속
- 상속의 장단점
2-1. 상속의 장점
2-2. 상속의 단점 - is-a 관계
- super.와 super();
4-1. super.
4-2. super();
4-3. this()와 super(), this.와 super. - 접근제한자 protected
- 오버라이딩(overriding)
객체 지향 프로그래밍(OOP, Object Oriented Programming) 3대 원칙이 캡슐화와 추상화, 상속, 다형성이다.
그 중 상속에 대해 배워보자.
1. 상속
SuperA a; |
△ ↑ ChildB b=a; |
- 상속에는 부모클래스와 자식클래스란 개념이 등장한다.
- 부모의 멤버(필드, 메소드)를 자식이 물려 받아 마치 자신의 멤버인 것처럼 사용할 수 있도록 만든 기술이다.
- 멤버 외에 타입 또한 상속이 된다. 여기서 이어져 다형성이 구축된다. 상속은 다형성의 토대이다.
- 자바는 단일 상속만 지원한다. 하나의 클래스만을 부모클래스로 가진다는 뜻이다.
- 예를 들어 아래와 같은 경우에는 자식클래스가 가진 a;라는 값이 어느 부모로부터 온 것인지 불분명하기 때문이다.
SuperA a;
SuperB a;
△
↑
ChildC a;
❗ 클래스 다이어그램에서 흰색 세모에 실선 모양을 가졌다면 상속을 뜻한다.
extends
- 클래스간 상속 시에는 extends 키워드를 사용한다.
public class Academy extends Company() {}
Company가 부모,
Academy가 자식클래스이다.
- extends 작성하는 순간 부모클래스로부터 모든 멤버를 상속 받은 것이다. 상속 자체는 이것으로 성립된다.
- 하지만 부모클래스의 생성자는 상속 받지 못한다.
- 또한 자식클래스라 할지라도 부모클래스가 가지고 있는 private 멤버는 접근이 불가능하다.
✅ 클래스의 상속에 대해 이해할 수 있다.
✅ 상속의 목적에 대해 이해할 수 있다.
2. 상속의 장단점
2-1. 상속의 장점
- 새로운 클래스를 작성할 때 기존에 작성된 클래스의 재사용을 가능케 한다.
- 클래스간 계층 관계가 형성되어 다형성 문법의 토대가 된다. 상속이 있기에 다형성 문법 또한 적용이 가능하게 된다.
2-2. 상속의 단점
- 부모클래스 변경사항이 생겼을 때 자식클래스의 정상 동작 여부를 예측하기 힘들다. 부모클래스의 변동이 자식클래스에 고스란히 영향을 미치는 것이다.
- 자식클래스가 물려 받아 사용하는 기능들을 부모클래스에서 뺄 수도 없다. 수정/삭제에 있어 자식클래스까지 고려해야만 하는 것이다.
- 부모클래스로부터 물려 받은 기능이 자식클래스에 무의미할 수 있다. 구조적으로 알맞지 않은데, 혹은 필요하지 않은데도 상속을 취하면 오히려 좋지만은 않게 작용할 수 있다.
✅ 상속의 장단점에 대해 이해할 수 있다.
3. is-a 관계
❗ 위와 같은 장단점을 고려해 is-a 관계가 성립되는 경우에만 상속을 사용하도록 한다!
is-a 관계
- "자식클래스는 하나의 부모클래스이다."
- is-a 관계가 성립이 되는 경우에 상속을 사용한다.
Circle is a Shape(o) / Shape is a Circle(x)
FireCar is a Car(o) / Car is a FireCar(x)
RacingCar is a Car(o) / Car is a RacingCar(x)
============================
Circle 클래스는 하나의 Shape 클래스이다.
Rectangle, Triangle 등 자식클래스는 더 많은 종류일 수 있다.
✅ 상속의 특징에 대해 이해할 수 있다.
4. super.와 super();
4-1. super.
super.getInformation();
- 부모클래스의 인스턴스 주소를 보관하는 레퍼런스 변수이다.
- 부모 인스턴스가 가지고 있는 값을 참조하기 위해 쓴다.
4-2. super();
- super();는 부모의 기본 생성자를 호출하는 구문이다. 이때 매개변수 타입, 개수, 순서가 일치하는 부모생성자를 호출하게 된다.
- 부모클래스가 가지는 private 생성자는 접근 불가하다. 그밖에 나머지 생성자는 호출 가능하다.
public FireCar() {
super();
}
- ctrl + 생성자명 클릭하면 부모클래스의 기본 생성자인 public Car() {} 가리키고 있음을 확인할 수 있다.
public RacingCar() {
System.out.println("RacingCar 클래스 기본 생성자 호출됨...");
}
===========================
Car 클래스의 기본 생성자 호출됨...
RacingCar 클래스 기본 생성자 호출됨...
- 생성자 안에 super(); 라고 명시하지 않아도 컴파일러가 자동 생성해준 예시이다.
- 모든 생성자에는 컴파일러가 맨 첫 줄에 super();를 자동 추가한다. 때문에 명시적, 묵시적 사용 모두 가능하다.
public class ProductDTO extends Object {}
❗ 모든 클래스는 Object.class의 후손이다.
부모의 부모클래스를 명시하지 않은 상황에서도 생성자 안에 super(); 구문이 호출된다.
java.lang.Object 클래스의 생성자가 호출되는 것이다.
즉 모든 클래스는 Object.clss를 super 클래스로 가지며, 모든 클래스는 Object.class의 후손이다.
FireCar fireCar = new FireCar();
fireCar.soundHorn(); *Car 클래스가 가진 기능
fireCar.run(); *Car 클래스가 가진 기능
==========================
Car 클래스의 기본 생성자 호출됨...
FireCar 클래스의 기본 생성자 호출됨...
- 자식클래스의 해당 생성자가 호출될 시 그보다 이전에 Car 클래스 호출 내용이 출력된다. 즉 부모클래스-자식클래스 순으로 호출된다.
super();
- 부모클래스 기본 생성자 호출
- 부모클래스의 기본 생성자를 없앤다면 곧바로 super();를 사용한 자식클래스에서 컴파일 에러 발생한다. 이처럼 영향을 받기 때문에 고려하여 작성해야 한다.
super(code, brand, name, price, manufacturingDate);
- 부모클래스 매개변수 있는 생성자 호출
4-3. this()와 super(), this.와 super.
this()와 super()
- this()는 해당 클래스의 생성자를 호출하는 구문이다. 자식클래스에서 작성될 때는 자식클래스 자신에게서 불러오는 것을 말한다.
- this(), super() 둘 다 첫 줄에 와야 한다. 그렇지 않은 경우 컴파일 에러가 발생한다: Constructor call must be the first statement in a constructor
- 한 곳에서 두 가지를 혼용하면 결국 다시 한 번 생성자를 호출하는 것이기 때문이다. 생성자 두 번 호출은 허용되지 않는다.
this.와 super.
- 설정자(setter)와 접근자(getter)는 선언 시부터 public으로 작성되기 때문에 이를 불러올 때 자식클래스가 따로 작성할 필요가 없다. 자식 클래스에 추가된 필드에 대해서만 설정자-접근자 생성해주면 된다.
- 자식클래스의 필드는 this.을 활용해 작성한다.
- public으로 작성된 만큼 필드값을 반환하고자 할 때에도 아래 예시 둘 다 사용 가능하다.
this.getCode()
super.getCode()
- 부모클래스에서 작성한 접근자(getter)를 이용해서 부모 필드가 가지고 있는 값을 불러와 문자열 합치기 할 수 있다.
부모가 가진 멤버는 super.와 this. 둘 다 사용이 가능하다. - 하지만 코드의 의미를 명확히하기 위해 부모클래스로부터 온 것은 super.를 사용하는 것이 좋다.
- 한편, 다음과 같은 컴파일 에러 사항에는 주의해야 한다: java.lang.StackOverflowError
super.getInformation() : 정상적으로 부모의 메소드 호출한다.
this.getInformation() : 재귀호출이 일어나며 StackOverflowError 발생한다.
getInformation() : this.이 자동 추가되어 재귀호출 일어난다.
stack |
. . getInformation getInformation getInformation main |
- 자식클래스 자신에게서 자신에게로 호출만 계속되고 리턴이라는 로직이 만들어지지 않아 stack에 오버플로우 발생한 에러이다.
✅ super에 대해 이해할 수 있다.
✅ super와 this의 차이를 이해할 수 있다.
5. 접근제한자 protected
- 자식클래스가 가진 멤버가 없는 상황에서도 부모클래스의 필드와 메소드를 전부 사용할 수 있다.
- 단, 부모클래스의 private 멤버는 접근이 불가능하다.
- 이때는 해당 멤버의 접근제한자를 private → protected로 바꿔 사용할 수 있다.
예를 들어 부모가 가지고 있는 멤버인 private boolean isRunning() 메소드를 사용해야 할 경우
부모클래스에서 접근제한자를 private → protected로 변경한다.
protected boolean isRunning()
- 접근제한자별 허용 범위는 다음과 같다.
구분 | 해당 클래스 내 | 같은 패키지 내 | 후손 클래스 내 | 전체 | |
+ | public | O | O | O | O |
# | protected | O | O | O | |
~ | (default) | O | O | ||
- | private | O |
✅ 접근제한자별 허용 범위를 이해하고 사용할 수 있다.
✅ 접근제한자 protected의 특징을 이해하고 사용할 수 있다.
6. 오버라이딩(overriding)
- 자바에서 상속이란 기본적으로 부모가 가진 멤버를 자식이 사용할 수 있는 것이다. 하지만 더 나아가서 부모클래스의 확장(extend)이라는 개념을 가질 수 있다.
- 자식클래스만의 추가적인 멤버 작성이 가능하며, 메소드 재정의(overriding)이라는 기술을 이용해서 부모가 가진 메소드를 재정의하는 것도 가능하다.
@Override 어노테이션
- 부모로부터 상속 받은 필드를 자식클래스에서 재정의할 때 사용된다.
- 오버라이딩이 정상적으로 작성된 것인지 체크하는 기능이다. 올바르게 작성했다면 어노테이션 없이도 작동 가능하나, 확인을 위해서라도 반드시 명시하는 것이 좋다.
- JDK 1.5부터 추가된 문법으로 오버라이딩 성립 요건을 체크하여 성립되지 않는 경우 컴파일 에러를 발생시킨다.
@Override
public void soundHorn() {
}
- 예를 들어 부모클래스에서 가진 메소드명과 다르게 입력하면, 재정의할 대상이 아니므로 오버라이딩 어노테이션을 삭제하라는 컴파일 에러 발생한다. 이처럼 오버라이딩 성립 여부 체크 기능을 수행한다.
fireCar.sprayWater();
// car.sprayWater();
- 한편, 부모클래스의 인스턴스로는 자식클래스의 인스턴스가 가진 기능을 사용할 수 없다.
- 자식은 부모 멤버에 접근해서 자신의 것처럼 사용 가능하지만, 반대의 경우는 허용되지 않는다.
- 이렇게 상속은 자식클래스로 하여금 부모가 가진 멤버를 사용하면서 스스로의 기능 확장까지 가능하도록 한다.
- 부모 클래스로부터 받은 모든 기능을 오버라이딩 및 커스터마이징 하는 것은 결국 새로운 클래스를 만드는 것과 다르지 않다. 때문에 반드시 상속이 필요한 구조에만 활용될 수 있도록 한다.
- 접근제한자를 부모보다 더 넓은 범위로 바꿔 오버라이딩 할 수 있다.
부모 protected void method(String str) {}
자식 public void method(String str) {}
이렇게는 가능하나 자식이 private으로 옮겨가는 경우는 불가하다.
❗ 오버라이딩 성립조건
1. 메소드 이름 동일
2. 메소드 리턴 타입 동일
3. 매개변수의 타입, 개수, 순서가 동일
4. private 메소드는 오버라이딩 불가능
5. final 키워드가 사용된 메소드는 오버라이딩 불가능
6. 접근제한자는 부모 메소드와 같거나 더 넓은 범위여야 함
7. 예외처리는 같은 예외이거나 더 구체적(하위)인 예외를 처리해야 함
❗ final 클래스는 상속 불가 클래스이다.
final 키워드는 지역변수, 필드, 메소드 등에서 사용해왔다.
A. 지역변수(local variable) 사용 예 > final int NUM=10;
B. 필드(field) 사용 예 > public static final double PI = 3.1415...;
C. 메소드(method) 사용 예 > public final void finalMethod() {}
클래스에도 이 final 키워드를 넣을 수 있는데, final 클래스는 상속 불가의 의미를 가진다.
D. 클래스(class) 사용 예 > class public final class ___ {}
오버라이딩과 오버로딩
- 기술적으로 닮은 개념은 아니나 발음이 비슷해 면접 시 단골 질문으로 나온다. 각각의 개념만 잘 정리해두도록 하자.
오버라이딩(overriding) | 오버로딩(overloading) |
하위 클래스에서 상위 클래스의 메소드 재정의 | 같은 클래스에서 메소드 정의 |
메소드 이름 동일 매개변수 동일(타입, 개수, 순서) 리턴 타입 동일 |
메소드 이름 동일 매개변수 다름(타입, 개수, 순서) 리턴 타입 상관 없음 |
같거나 더 넓은 접근제한자 허용 |
접근제한자와 상관 없음 |
예외처리와 관련 있음 | 예외처리와 상관 없음 |
✅ 오버라이딩에 대해 이해할 수 있다.
✅ 오버로딩과 오버라이딩의 차이에 대해 이해할 수 있다.
'Java' 카테고리의 다른 글
[JAVA/수업 과제 practice] 상속 Lv. 1~2 (0) | 2022.01.06 |
---|---|
[JAVA] 9. 다형성 | 추상클래스 | 인터페이스 (1) | 2022.01.05 |
[JAVA/수업 과제 practice] 객체배열 Lv. 1~2 (0) | 2022.01.03 |
[JAVA] 7. 객체배열 (0) | 2022.01.03 |
[JAVA] 6-4. 클래스변수, 인스턴스변수, 지역변수, 초기화 순서 (0) | 2022.01.03 |