Java] Inheritance

상속은 재활용성과 유지보수, 확장성에 좋다고들 한다.

그러나 재활용성에 대해서는 논의가 많다. 코드의 재활용을 위해서 상속을 사용한다기보다는 연관된 일련의 클래스에 대한 공통적인 규악을 정의한다고 아는 것이 좋다.

상위 클래스 : parent class, base class, super class

하위 클래스 : child class, derived class, sub class

하위 클래스의 생성자에서는 무조건 상위 클래스의 생성자가 호출되어야 한다.

상위 클래스의 인스턴스가 먼저 생성되고, 하위 클래스의 인스턴스가 생성된다.

객체지향이 재활용의 관점에서 실패한 이유

  • 클래스 하나를 재활용하는 것이 새롭게 디자인하는 것보다 더 큰 노력이 든다.
  • 재활용성을 고려해서 클래스를 디자인할 경우, 설계에 필요한 시간이 몇 배 더 길어진다.

재활용에 대한 이슈는 객체지향 패러다임에서 CBD라는 패러다임으로 옮겨 간지 오래이다. CBD 역시 객체지향을 기반으로 형성된 패러다임이기 때문에 중요하다.

CBD(Component Based Development)

클래스 단위의 재활용을 논의하지 않고, 자바의 패키지 혹은 그 이상의 규모에 대한 재활용을 논의한다.

Super

상위 클래스의 생성자, method 호출

1
2
3
4
5
6
7
8
9
10
11
public class AAA {
int num1;
AAA(){};
}

class BBB extends AAA {
int num2;
BBB(){
super(); //쓰지 않을 시, 자동으로 컴파일러가 추가
};
}

기본생성자의 경우에만 자동으로 컴파일러가 추가한다. 파라미터가 있을 경우에는 super() 안에 인자를 넣어줘야 한다.

Override

상위 클래스에 정의된 메소드의 구현 내용이 하위 클래스에서 구현할 내용과 맞지 않는 경우,

하위 클래스에서 동일한 이름의 메서드를 재정의 할 수 있다.

toString

: toString 메서드는 인스턴스의 정보를 문자열의 형태로 반환하기 위한 메서드

가급적이면 toString 메서드를 오버라이딩 해서 인스턴스에 대한 정보를 적절히 표현할 수 있도록 하는 것이 좋다.

instanceof

상속 관계를 바탕으로 형변환이 가능한지를 묻는 연산자이다.

return : true/false

Ploymorphism, 다형성

하나의 코드가 여러 자료형으로 구현되어 실행되는 것

같은 코드에서 여러 실행 결과가 나온다.

정보은닉, 상속과 더불어 객체지향 프로그래밍의 가장 큰 특징 중 하나이다.

객체지향 프로그래밍의 유연성, 재활용성, 유지보수성에 기본이 되는 특징

다형성의 장점

  • 하나의 코드가 다양한 구현을 실행

    다양한 여러 클래스를 하나의 자료형(상위 클래스)으로 선언하거나 형변환하여 각 클래스가 동일한 메서드를 오버라이딩 한경우

  • 유지보수 용이

    유사한 클래스가 추가되는 경우 유지보수에 용이하며, 각 자료형마다 다른 메서드를 호출하지 않으므로 코드에서 많은 if문이 사라진다.

IS-A관계(is a relationship : inheritance)

: 일반적인 개념과 구체적인 개념과의 관계

‘일반 고객 / 골든 고객 / VIP 고객’ 이런 식으로 고객의 정보가 있을 때의 관계를 나타냅니다.

HAS-A관계(composition)

HAS-A관계는 상속의 조건은 되지만, 복합 관계로 이를 대신하는 것이 일반적이다.

HAS-A관계 : 상속

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
/** HAS-A관계 : Inheritance **/
public class HASInheritance {
public static void main(String[] args) {
Police police = new Police(5, 3);
police.shot();
police.putHandcuff();
}
}

class Gun {
int bullet; //장전된 총알의 수

public Gun(int bullet) {
this.bullet = bullet;
}

public void shot() {
System.out.println("빵!");
this.bullet--;
}
}

class Police extends Gun {
int handcuffs; //소유한 수갑의 수

public Police(int bullet, int handcuffs) {
super(bullet);
this.handcuffs = handcuffs;
}

public void putHandcuff() {
System.out.println("체포!");
this.handcuffs--;
}
}

HAS-A관계 : 복합 관계

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
/** HAS-A관계 : Composite **/
public class HASComposite {
public static void main(String[] args) {
PoliceComposite haveGun = new PoliceComposite(5, 3); //총알5 수갑3
haveGun.shot();
haveGun.putHandcuff();

PoliceComposite dontHaveGun = new PoliceComposite(0, 3); //총알0 수갑3
dontHaveGun.shot();
dontHaveGun.putHandcuff();
}
}

class GunComposite {
int bullet; //장전된 총알의 수

public GunComposite(int bullet) {
this.bullet = bullet;
}

public void shot() {
System.out.println("빵!");
this.bullet--;
}
}

class PoliceComposite {
int handcuffs; //소유한 수갑의 수
Gun pistol; //소유하고 있는 권총

public PoliceComposite(int bullet, int handcuffs) {
this.handcuffs = handcuffs;
if(bullet != 0) {
this.pistol = new Gun(bullet);
} else {
this.pistol = null;
}
}

public void putHandcuff() {
System.out.println("체포!");
this.handcuffs--;
}

public void shot() {
if(this.pistol == null) {
System.out.println("틱!(총알 없음)");
} else {
pistol.shot();
}
}
}

상속으로 묶인 두 개의 클래스는 강한 연관성을 띤다.

Gun Class를 상속하는 Police 클래스로는 총을 소유하는 경찰만 표현 가능하다.

하지만, 복합 관계의 경우에는 권총을 소유하지 않은 경찰도 표현이 가능하다.

경찰이 총만이 아닌 경관봉을 들어야할 때도 있는 점들을 고려한다면 복합 관계로 구현하는 것이 더 편리할 것이다.

다운 캐스팅

하위 클래스로 형 변환

묵시적으로 상위 클래스 형변환도니 인스턴스가 원래 자료형(하위 클래스)으로 변환되어야 할 때 다운 캐스팅이라 함

1
2
3
Customer vc = new VIPCustomer(); //묵시적
VIPCustomer vCustomer = (VIPCustomer)vc; //명시적
Eagle eagle = (Eagle) hAnimal;

이렇게 해도 컴파일 에러가 발생하지 않다가 실행하면

1
Exception in thread "main" java.lang.ClassCastException: Chater5.ploymorphism.Human cannot be cast to Chater5.ploymorphism.Eagle

오류가 발생한다.

이러한 일을 방지하기 위해서 instanceof을 사용한다.

오버라이딩을 사용할 수 있을 때는 다형성을 사용하여 처리하고, 안될 경우에는 다운 캐스팅을 이용하면 된다.

소스 참고 링크

https://github.com/TaeJuneJoung/Java/blob/master/src/Chapter5/ploymorphism/AnimalTest.java

Final

final class

클래스에 final선언을 해주면 “이 클래스를 상속하는 것을 허용하지 않음”이라는 뜻이 담기게 된다.

  • 상속X

final method

메서드에 final선언을 해주면 “이 메서드를 오버라딩 하는 것을 허용하지 않음”이라는 뜻이 담기게 된다

  • 오버라이딩X