티스토리 뷰

Java/문법

7. 상속 : extends

알 수 없는 사용자 2018. 10. 11. 02:52


 이번 포스팅에서는 상속에 대해

 알아보도록 하겠습니다.

상속은 객체에 이어서 

완벽하게 이해하지 않는다면

이후의 자바 내용을 이해하기 너무 어려울 겁니다.

반드시 완벽하게 숙지하고 넘어갑시다.


=======================================================


상속 : extends



1. 상속? extends가 무엇이지?


사전적 의미의 상속은 '일정한 친족 관계가 있는 사람 사이에서,  사람이 사망한 에 다른 사람에게 재산에 관한 권리와 의무의 일체를 이어 주거나다른 사람이 사망한 사람으로부터  권리와 의무의 일체를 이어받는 일'이라고 정의되어 있습니다. 쓸데없이 긴 느낌인데 그냥 간단하게 '뒤를 이음, 물려준다.'라는 뜻으로 자바에서는 해석하는 것이 편할 것입니다.


 그렇다면 자바에서의 상속은 무엇일까요? 

우리는 지금까지 클래스 한 개를 생성하고 해당 클래스의 객체를 생성하여 사용했습니다. 그런데 만약 하나의 클래스에서 해당 클래스의 객체밖에 생성할 수 없다면 상당히 불편할 것입니다. 


 이해를 쉽게 하기 위해 예를 들어보겠습니다.

스타크래프트라는 게임에서 배럭, 팩토리 라는 건물이 있습니다. 배럭에서는 마린, 메딕, 고스트, 파이어뱃 유닛을, 팩토리에서는 탱크, 골리앗, 벌처를 생산할 수 있습니다.

이것을 만약 객체로 생성한다 생각하면 각 유닛마다 클래스를 설계해야합니다. 

 하지만 배럭에서 나오는 유닛과 팩토리에서 나오는 유닛은 공통적인 특성을 가진 유닛입니다. (ex. 마린, 메딕, 고스트, 파이어뱃은 크기와 특성이 같은 유닛들입니다.)

그렇다는 것은 각 건물에서의 유닛들은 클래스 내에 같은 기능과 데이터를 가진다는 것입니다. 같은 코드가 반복된다는 낭비와 객체를 생성해서 다룸에도 매우 비효율적입니다.




그렇기 때문에 공통으로 가지는 기능과 데이터는 배럭이라는 상위 클래스로 만들고 그 상위 클래스를 포함하고 추가로 특정 기능을 가진 각 유닛의 클래스(하위 클래스)를 생성할 수 있습니다. 이때의 상위클래스를 포함하여 하위클래스를 만든 것을 상속이라 하며 더불어 확장이라는 의미로 사용되기도 합니다.





2. 상속의 특징?


 1) 부모 클래스와 자식 클래스는 extends에 의하여 정해집니다.

 2) 하나의 부모 클래스는 여러 개의 자식 클래스를 가질 수 있지만 하나의 자식 클래스는 한 개의 부모 클래스만 가져야 합니다.

 3) 부모 클래스로부터 상속받은 자식 클래스는 부모 클래스의 모든 변수와 메소드를 사용할 수 있지만, 부모 클래스는 자식 클래스를 사용할 수 없습니다.

 4) 자식 클래스는 또 다른 클래스의 부모 클래스가 가능합니다.

 5) 자식 클래스는 부모 클래스의 메소드를 오버라이드하여 사용할 수 있습니다.

 6) 부모 클래스가 그 위의 상위 클래스로부터 받은 자원도 자식 클래스가 사용할 수 있습니다.  





3. 상속 어떻게 사용할까?


상속을 이용하는 방법을 알아봅시다.

위에서 예시로 든 배럭 클래스, 마린 클래스 그리고 테란 클래스를 생성해서 알아보도록 하겠습니다.





Marine 클래스는 마린을 생성할 때 사용하는 클래스입니다.

Marine 클래스는 Barrack에서 생산됨으로 Barrack 클래스를 부모 클래스로 상속합니다.

Barrack 클래스 또한 Terran에 속함으로 Terran Class를 부모 클래스로 상속합니다. 


부모 클래스라 하여 Terran Class가 가장 큰 느낌을 받을 수 있지만 상속이란 개념은 부모 클래스의 리소스를 이용해서 추가로 자신의 기능을 확장하는 개념이기 때문에 위 그림처럼 Marine Class를 가장 크게 표현합니다.




1) extends를 이용해 클래스를 현합니다.


public class Terran { }
public class Barrack extends Terran { }
public class Marine extends Barrack { }

각 클래스의 선언 부를 보면 extends를 사용하여 부모클래스를 상속하는 것입니다. 그렇기 때문에 Marine <- Barrack -< Terran 순으로 상속하는 것입니다.




2) Terran Class에는 보유하고 있는 미네랄과 가스 자원이 있고 미네랄과 가스 자원을 출력할 수 있는 기능을 구현합니다.


public class Terran {
static int mineral;
static int gas;

Terran() {
mineral = 1000;
gas = 1000;
}

String getResource() {
return mineral + " / " + gas;
}

String tell() {
return "Terran Class";
}
}

테란 객체가 생성될 때 미네랄, 가스가 1000으로 초기화되고 getResource() 메소드를 통해 미네랄과 가스를 볼 수 있도록 구현합니다.




3) Barrack Class에는 별다른 맴버 변수는 없이 Barrack 객체가 생성될 때 미네랄이 150원 소요되도록 만듭니다.


public class Barrack extends Terran {
Barrack() {
super();
mineral -= 150;
}

String tell() {
return "Barrack Class";
}
}

Barrack 클래스만 보면 mineral이라는 변수가 존재하지 않은데 연산을 하고 있습니다. 이는 Barrack 클래스가 Terran 클래스를 상속받고 있기 때문에 Terran의 리소스를 사용할 수 있는 것입니다.




4) Marine Class에는 공격력과 방어력을 가진 맴버 변수와 객체가 생성될 때 미네랄 50원이 소요되도록 설계합니다. 또한 업그레이드를 위한 기능을 구현합니다.


public class Marine extends Barrack {
int attack;
int defense;

Marine() {
super();
mineral -= 50;
attack = 10;
defense = 5;
}

void upgrade(int data) {
attack += 5;
defense +=5;
}
String tell() {
return "Marine Class";
}
}

마찬가지로 Marine 클래스가 Barrack 클래스를 상속받고 있는데 Barrack 클래스 또한 Terran 클래스를 상속받고 있기 때문에 Terran 클래스의 리소스인 mineral을 제어할 수 있는 것입니다.




5) 객체를 생성해보고 결과물을 살펴봅시다.


class Example {
public static void main(String[] args) {
Terran b = new Marine();
System.out.println(b.tell());
System.out.println(b.getResource());
}
}



Terran 객체와 Barrack 객체를 생성하지 않았는데 Marine 객체의 생성만으로 Terran 객체의 미네랄이 소요된 것을 볼 수 있습니다. 미네랄이 소요된 값을 보면 Marine 객체 생성 비용과 Barrack 객체 생성 비용의 합한 금액입니다.


이처럼 상속 관계에서는 맨 하위 클래스의 객체 생성만으로 상위 클래스의 객체생성까지 진행됩니다. 엄밀히 말하면 상위 클래스 객체가 먼저 생성되고 하위 클래스 객체가 마지막으로 생성되는 것입니다. 그 이유는 상속이란 확장의 개념이기 때문에 부모 클래스의 리소스를 포함하고 있습니다. 그렇기 때문에 부모 클래스 객체를 먼저 생성하고 차례대로 자식 클래스가 생성되는 것입니다. 이러한 과정은 super() 메소드에 의해서 일어납니다.


- super() :

자식 클래스 객체를 생성할 때 부모 클래스를 먼저 생성하기 위한 메소드입니다. 만약 부모 클래스가 기본 생성자로 구현되어 있다면 super()를 적지 않아도 자동으로 생성되지만, 만약 생성자마다 파라미터값을 인자로 받는다면 super() 메소드에 그에 따른 파라미터 값을 전달하여 부모 클래스의 생성자를 호출하여야 합니다.






4. 상속의 장점은?



1) 가장 큰 이유로는 재활용이라는 측면입니다.

 당연히 각자의 기능을 단계별로 상속 관계로 설계했을 때 만약 배럭에 새로운 유닛이 업데이트되었다면 기존에 존재하던 배럭 클래스는 유지한 채 새로운 유닛 클래스를 생성해서 배럭 클래스를 상속받아 구현하면 배럭클래스를 재활용해 효율적으로 코드 설계가 가능할뿐더러 간결하고 가독성이 좋아질 것입니다.



2) 자식 클래스 설계 시 중복되는 맴버를 미리 부모 클래스에 작성해 놓으면, 자식 클래스에서는 해당 맴버를 작성하지 않아도 됩니다.

 배럭이 지어질 때, 마린이 생산될 때 다른 작업 없이 바로 부모 클래스에 접근하여 리소스를 사용할 수 있었습니다. 



3) 다형성의 문법적 토대를 마련할 수 있습니다.

 다형성이라는 부분은 상속에서뿐만 아니라 후에 다룰 오버로딩, 오버라이드에서도 연관되는 내용입니다. 간단하게 집고 넘어가겠습니다.


Marin 객체와 같은 형태로 Medic 객체를 생성하겠습니다.

그렇다면 Marin 클래스와 Medic은 둘 다 Barrack에게 상속받는 최하위 자식 클래스가 됩니다.


public class Medic extends Barrack {
int attack;
int defense;

Medic() {
mineral -= 50;
attack = 10;
defense = 5;
}

void upgrade(int data) {
attack += 5;
defense +=5;
}
String tell() {
return "Medic Class";
}
}

class Example {
public static void main(String[] args) {
Terran c = new Marine();
Terran b = new Medic();
System.out.println(b.tell());
System.out.println(c.tell());
}
}

메인 클래스를 다음과 같이 작성하여 출력해보겠습니다.




최하위 자식 클래스인 Marin과 Medic을 생성한다면 제일 상위 클래스인 Terran 클래스 타입으로 생성할 수 있습니다.

이게 바로 다형성이라는 큰 장점입니다. 같은 타입의 변수에 다른 객체를 생성할 수 있다는 것입니다.

이렇게 된다면 상황에 따라 생성해야 할 객체를 생성할 수 있다는 유동적?인 상황을 연출할 수 있게 될 것입니다.

(예를 들어 a 카페에는 손님, b 카페에는 바리스타)


공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/11   »
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
글 보관함