📌 상속에 대해서 정확히 이해하자.
📌 상속의 예제 코드를 살펴보자.
📌 다중상속을 지원하지 않는 자바의 인터페이스를 살펴보자.
📌 T메모리와 함께 살펴보자.
자바에서 상속은
inheritance
(상속) 가 아닌extends
(확장)이라는 예약어를 사용한다.
상속은 상위 클래스의 특성을 하위 클래스에서 재사용하고, 필요한 특성을 추가하여 확장해 사용한다.
상속이라고 생각하면 생물 파트의 유전자 문제의 조직도, 계층도가 생각난다.
그런데 상속은 그것보다는 ... 🤔 병합된 엑셀표로 생각해보자!!
객제 지향의 상속은 하위클래스가 상위클래스에 포함된다.
예를 들어 동물
클래스를 상속받은 포유류
는 동물의 속성을 모두 재사용하면서, 추가적으로 젖을 물리는 행위를 추가해서 확장한다. 이때 포유류는 동물에 포함되면서, 동물인 것이다.
그러나 가족 구성원을 나타내는 데 쓰이는 계층 구조로는 이런 포함의 관계를 설명하고 직관적으로 이해하기 어렵다.
조직도에서는 자식이 부모에 포함되고, 부모인 것은 아니기 때문이다. 그래서 혹시 상속이란 개념이 헷갈린다면 포함의 벤 다이어그램으로 이해하는 것은 어떨까?
동물 로아 = new 포유류();
// 포유류라는 객체 인스턴스를 동물 로아에 집어넣었다.
// 즉 로아는 동물이다.
is a kind of
관계를 만족해야한다.보통 상속 관계를 표현하는 is a
를 더 많이 들어봤을 것이다.
하지만 상속관계를 더 명확히 하는 표현은 종류를 뜻하는 kind of
가 더 적절하다.
😎 펭귄 is a kind of 조류
➡️ 펭귄은 조류의 한 종류이다.
객체 지향은 인간이 현실을 인식하는 논리대로 프로그래밍 할 수 있게 해준다.
🤔 사람은 박쥐, 고래, 참새를 어떻게 인식할까?
👤 박쥐는 "조류"이면서, "동물"이고, "생물"이에요!!
즉, 박쥐는 생물 분류 내, 동물 분류 내, 조류이다.
➕ 더 나아가면? 박쥐를 조류로도 인식하고, 동물로도 인식한다!!
➡️ 이런 인간의 인식 방법을 프로그래밍으로 가능하게 하는 것이 "상속"이다!!
동물 박쥐A씨 = new 조류();
//프로그래밍인 박쥐를 동물로 인식한다.
//🤔... 코드로 살펴보자 ⬇️⬇️
🤔 박쥐, 고래, 참새, 펭귄은 모두 동물!!
package OOP03.inheritance01;
public class 동물 {
String myClass;
public 동물() {
myClass = "동물";
}
void showMe() {
System.out.println("myClass = " + myClass);
}
}
package OOP03.inheritance01;
public class 포유류 extends 동물 {
public 포유류() {
myClass = "포유류";
}
}
package OOP03.inheritance01;
public class 고래 extends 포유류 {
public 고래() {
myClass = "고래";
}
}
package OOP03.inheritance01;
public class 펭귄 extends 조류 {
public 펭귄() {
myClass = "펭귄";
}
}
package OOP03.inheritance01;
public class 조류 extends 동물 {
public 조류() {
myClass = "조류";
}
}
package OOP03.inheritance01;
public class 박쥐 extends 포유류 {
public 박쥐() {
myClass = "박쥐";
}
}
package OOP03.inheritance01;
public class 참새 extends 조류 {
public 참새() {
myClass = "조류";
}
}
하위클래스에 showMe를 따로 작성하지 않아도 재사용이 가능했다.
하위클래스 조류,포유류는 모두 동물이니까!
package OOP03.inheritance01;
public class Driver01 {
public static void main(String[] args) {
// 😎 우와 extends를 쓰니까 재사용할 수 있네!! showMe를 하나하나 만들지 않아도 돼!!
동물 animal = new 동물();
포유류 mammalia = new 포유류();
조류 bird = new 조류();
고래 whale = new 고래();
박쥐 bat = new 박쥐();
참새 sparrow = new 참새();
펭귄 penguin = new 펭귄();
animal.showMe();
mammalia.showMe();
bird.showMe();
whale.showMe();
bat.showMe();
sparrow.showMe();
penguin.showMe();
//🤔 흠... 근데 하위 클래스 모두 상위 클래스이잖아.
//객체 참조 변수는 모두 동물이잖아!!
}
}
각각의 하위 클래스는 모두 상위클래스이다.
package OOP03.inheritance01;
public class Driver02 {
public static void main(String[] args) {
//😎 하위 클래스는 모두?? 상위 클래스
동물 animal = new 동물();
동물 mammalia = new 포유류();
동물 bird = new 조류();
동물 whale = new 고래();
동물 bat = new 박쥐();
동물 sparrow = new 참새();
동물 penguin = new 펭귄();
animal.showMe();
mammalia.showMe();
bird.showMe();
whale.showMe();
bat.showMe();
sparrow.showMe();
penguin.showMe();
//🤔 흠... 객체 참조 변수명은 다 다르지만 타입은 동물로 모두 동일하네..?
// 이 변수를 모두 한번에 사용할 수 있지 않을까?
}
}
헉 이건 진짜 좋당~
package OOP03.inheritance01;
public class Driver03 {
public static void main(String[] args) {
동물[] animals = new 동물[7];
animals[0] = new 동물();
animals[1] = new 포유류();
animals[2] = new 조류();
animals[3] = new 고래();
animals[4] = new 박쥐();
animals[5] = new 참새();
animals[6 ] = new 펭귄();
for (int index = 0; index < animals.length; index++) {
animals[index].showMe();
}
}
}
🙅 클래스끼리의 다중 상속은 지원하지 않는다.
🙆♂️ 인터페이스를 통해 다중 구현을 지원한다.
➕ 자바에서 다중 상속을 지원하지 않는 경우는 포스팅했던 것 같다. 해당 글 보러가기
흠... 너무 짧게 포스팅했나..? 하여튼... 득보다 실이 많아서 과감하게 다중상속을 금지했다.
즉, 해당 클래스가 해당 메서드를 구현해야 하고, 그러한 클래스가 상위-하위 관계가 아닐 때 인터페이스를 활용할 수 있다.
사실 인터페이스는 더 세세한 내용이 많다. 그리고 심화적인 이야기도 해야한다. "인터페이스 분할 원칙"이라는 것도 있고... 그렇지만 세세한 내용은 중간 단계보다는기초 단계의 글을 확인하길 바라고, 심화적인 부분은 조금 더 나중에 이야기하겠다! (사실 내가 아직 공부 안함, 그런데 중요한건 기억남ㅎ)
상위클래스는 하위클래스에게 물려줄 특성이 많을수록 좋다.
인터페이스는 각각 구현을 강제할 메서드가 적을 수록 좋다.
package OOP03.inheritance01;
public interface 헤엄칠수있는 {
void swim();
}
package OOP03.inheritance01;
public class 고래 extends 포유류 implements 헤엄칠수있는 {
public 고래() {
myClass = "고래";
}
@Override
public void swim() {
System.out.println("🐋 🏊♂️");
}
}
package OOP03.inheritance01;
public class 펭귄 extends 조류 implements 헤엄칠수있는 {
public 펭귄() {
myClass = "펭귄";
}
@Override
public void swim() {
System.out.println("🐧 🏊♂️");
}
}
package OOP03.inheritance01;
public class Driver04 {
public static void main(String[] args) {
헤엄칠수있는[] ableToSwim = new 헤엄칠수있는[2];
ableToSwim[0] = new 고래();
ableToSwim[1] = new 펭귄();
for (int index = 0; index < ableToSwim.length; index++) {
ableToSwim[index].swim();
}
}
}
package OOP03.inheritance03;
public class Anlimal {
public String name;
public void showName() {
System.out.println("나는 " + name + "(이)야. 반가워");
}
}
package OOP03.inheritance03;
public class Penguin extends Anlimal{
public String habitat;
public void showHabitat() {
System.out.printf("%s는 %s에 살아\n", name, habitat);
}
}
package OOP03.inheritance03;
public class Driver {
public static void main(String[] args) {
Penguin proro = new Penguin();
//Aaimal 클래스의 인스턴스도 함께 힙영역에 생성된다.
//📌 하위 클래스의 인스턴스가 생성될 때 상위클래스의 인스턴스도 함께 생성된다.
proro.name = "뽀로로";
proro.habitat = "눈 덮인 숲속 마을";
proro.showName();
proro.showHabitat();
Anlimal pingu = new Penguin();
//Aaimal 클래스의 인스턴스도 함께 힙영역에 생성된다.
//📌 하위 클래스의 인스턴스가 생성될 때 상위클래스의 인스턴스도 함께 생성된다.
//📌 그러나 객체 참조 변수의 타입이 Ainmal로 암묵적 형변환이 일어난다.
// 암묵적 형변환의 경우 : 생성클래스의 멤버 변수, 메소드 👉 ❌
pingu.name = "핑구";
// pingu.habitat = "눈 덮인 숲속 마을";
pingu.showName();
// pingu.showHabitat();
}
}
📌 하위 클래스의 인스턴스가 생성될 때 상위클래스의 인스턴스도 함께 생성된다.
따라서 뽀로로가 참조하고 있는 인스턴스는 Penguin
인스턴스와 Animal
인스턴스가 함께 생성된다.
🤔 그러면 핑구는?
핑구 역시 하위클래스의 생성자로 인스턴스가 생성되면서 Penguin
인스턴스와 Animal
인스턴스가 함께 생성된다.
📌 그러나 객체 참조 변수의 타입이 Ainmal로 암묵적 형변환이 일어난다.
따라서 인스턴스는 Peguin
인스턴스도 생성되었다고 해서 사용할 수는 없다.
👉 암묵적 형변환
😅 지금보니까 조금 대충 정리하기는 했네...ㅎ
📌 암묵적 형변환이란
- 자식클래스가 부모클래스에게 상속받은 기능만 사용하도록 제한
- 기능의 제한으로 하위클래스의 멤버 사용 불가능❌
- 기능의 변경은 아님 : 오버라이딩된 하위클래스의 메서드 사용 가능 ⭕
📌 하위 클래스의 인스턴스가 생성될 때 상위클래스의 인스턴스도 함께 생성된다.
📌 그러나 객체 참조 변수의 타입이 Ainmal로 암묵적 형변환이 일어난다.
사실 이렇게 끝내면 의아한 사람이 많을 것이다!
상위클래스와 하위클래스의 묵시적 형변환을 하면 짝꿍으로 나오는게 메서드 오버라이딩이니까!!
그건 다음 글에서 포스팅하겠다~!