본문 바로가기
Java/Java

객체 지향 3대 원칙) 상속에 대해서, 상속 시 메모리 구조

by 박채니 2022. 3. 21.
SMALL

안녕하세요, 코린이의 코딩 학습기 채니 입니다.

 

개인 포스팅용으로 내용에 오류 및 잘못된 정보가 있을 수 있습니다.


상속이란?

- 부모 클래스의 멤버(필드, 메소드, 이너클래스)를 내려받아 자식 클래스 내부에 포함

부모 클래스는 자식 클래스의 공통적 특징을 모아 구성한 클래스

 

상속의 장점

① 코드의 중복성 제거

② 다형적 표현 가능

 

상속 문법

class 자식 클래스 extends 부모 클래스 {
	//...
}

단, 자바의 클래스는 다중 상속이 불가!!! (부모 클래스가 2개 이상일 때를 의미)

그 이유는, 만일 class A와 B 모두 data라는 필드를 포함하고 있을 때 class C가 상속을 하면 C 또한 data 필드를 갖고 있을 것입니다.

그럴 때 A의 data 값이 3이고, B의 data 값이 4일 때, C는 A클래스 값이 적용되면 3이 적용될 것이고 B클래스 값이 적용되면 4가 적용 될 것입니다.

이렇듯 다중 상속을 허용하게 된다면, 모호성이 발생하기 때문에 자바는 다중 상속이 불가합니다.

 

//부모 클래스
class Parent {
	String name;
	int age;
	
	public void say() {
		System.out.println("부모클래스");
	}
	
	public String information() {
		return "name = " + name + ", age = " + age;
	}
}

//자식클래스
class Child extends Parent {
	
}

부모 클래스인 Parent에 name, age 필드와 say(), information() 메소드를 정의하고 Parent 클래스를 상속 받은 Child 클래스를 정의하였습니다.

 

public class InheritanceBasicMain {
	public static void main(String[] args) {
		Child child = new Child();
		child.name = "자식클래스";
		child.age = 15;
		child.say();
		System.out.println(child.information());
	}
}

@콘솔출력값
부모클래스
name = 자식클래스, age = 15

Child 객체를 생성한 후 name, age필드에 값을 대입하고 say() 메소드, information() 메소드를 출력하였습니다.

Child 클래스 내부에는 아무런 코드가 정의되지 않았었는데, 부모 클래스로부터 물려받은 name, age필드를 가져와 값 대입을 할 수 있었으며 say() 메소드와 information메소드 또한 출력이 가능했습니다.

즉 Child 클래스에도 부모 클래스 내부에 있는 필드, 메소드가 보이진 않지만 정의가 되어있는 것이죠.

 

그렇다면, 부모 클래스는 단 하나의 자식 클래스만 상속할 수 있을까요?

아닙니다. 위에서 말한 다중 상속은 부모 클래스가 2개 이상이 불가한 것이고, 자식 클래스는 100개 1,000개든 상관없습니다.

//부모클래스
class Parent {
	String name;
	int age;
	
	public void say() {
		System.out.println("부모클래스");
	}
	
	public String information() {
		return "name = " + name + ", age = " + age;
	}
}

//Parent 자식 클래스1
class Child extends Parent {
	
}

//Parent 자식 클래스1
class OtherChild extends Parent {
	
}

Child 클래스와 OtherChild 클래스 모두 Parent 클래스를 상속하고 있으며, 위와 같은 상속 구조를 띄고 있습니다.

 

public class InheritanceBasicMain {
	public static void main(String[] args) {
//		Child child = new Child();
//		child.name = "자식클래스";
//		child.age = 15;
//		child.say();
//		System.out.println(child.information());

		OtherChild otherChild = new OtherChild();
		otherChild.name = "엄친아";
		otherChild.age = 20;
		otherChild.say();
		System.out.println(otherChild.information());
	}
}

@콘솔출력값
부모클래스
name = 엄친아, age = 20

마찬가지로 OtherChild 객체 생성 후 각 필드에 값 대입, 메소드 출력을 해보았습니다.

부모 클래스의 필드, 메소드를 상속 받아 사용한 것을 알 수 있습니다.

 

상속 받은 자식 클래스는 반드시 부모 클래스의 멤버만 사용해야할까요?
아닙니다. 자식 클래스에서도 필요한 멤버들을 추가할 수 있습니다.

Child 클래스에 필드, 메소드를 추가해보았습니다.

class Parent {
	String name;
	int age;
	
	public void say() {
		System.out.println("부모클래스");
	}
	
	public String information() {
		return "name = " + name + ", age = " + age;
	}
}

class Child extends Parent {
	String game = "LOL";
	
	public void doGame() {
		System.out.println(name + "가 " + game + "게임을 한다.");
	}
}

이렇게 되면, Child클래스에서 사용할 수 있는 필드는 상속 받은 부모 클래스의 name, age와 Child클래스의 game필드

사용할 수 있는 메소드는 상속 받은 부모 클래스의 say(), information()과 Child클래스의 doGame()메소드가 됩니다.

 

public class InheritanceBasicMain {
	public static void main(String[] args) {
		Child child = new Child();
		child.name = "자식클래스";
		child.age = 15;
		child.say();
		System.out.println(child.information());
		child.doGame();
	}
}

@콘솔출력값
부모클래스
name = 자식클래스, age = 15
자식클래스가 LOL게임을 한다.

 

자바에서는 다중 상속이 불가하다고 했습니다.

그렇다면 부모 클래스 + 자식 클래스의 멤버들을 사용하고 싶을 땐 어떻게 해야할까요?

자식 클래스를 상속하면 됩니다!

class Parent {
	String name;
	int age;
	
	public void say() {
		System.out.println("부모클래스");
	}
	
	public String information() {
		return "name = " + name + ", age = " + age;
	}
}

class Child extends Parent {
	String game = "LOL";
	
	public void doGame() {
		System.out.println(name + "가 " + game + "게임을 한다.");
	}
}

class GrandChild extends Child {
	
}

Child가 Parent를 상속하고 GrandChild가 Child를 상속하고 있습니다.

 

그렇다면 GrandChild에서 사용할 수 있는 멤버는 어떻게 될까요?

Parent의 name, age필드 + say(), information()메소드 / Child의 game 필드 + doGame()메소드가 됩니다.

그 이유는 Child에서 상속 받은 부모 클래스의 멤버들을 사용할 수 있으므로 부모 클래스의 멤버들을 포함하고 있다고 하였습니다.

따라서 Child를 상속하는 GrandChild 또한 Child의 멤버들을 사용할 수 있으므로 이처럼 사용이 가능한 것이죠.

public class InheritanceBasicMain {
	public static void main(String[] args) {
		GrandChild grandChild = new GrandChild();
		grandChild.name = "손자";
		grandChild.age = 3;
		grandChild.say();
		System.out.println(grandChild.information());
		grandChild.doGame();
	}
}

@콘솔출력값
부모클래스
name = 손자, age = 3
손자가 LOL게임을 한다.

이러한 상속 구조를 띄고 있습니다.

 

그렇다면, 어떻게 부모 클래스의 멤버들을 사용할 수 있는 것일까요?

메모리 구조를 확인해보겠습니다.

 

Child child = new Child();

클래스 영역(static영역)에는 선언된 자료형의 클래스와 부모 클래스가 모두 로딩됩니다.(그림은 생략)

 

이 때 참조변수 child는 Child 자료형으로 선언됐기 때문에 힙 메모리에 있는 Child 타입 객체만을 가리킬 수 있습니다.

JVM은 자식 클래스의 객체를 생성할 때 가장 먼저 부모 클래스의 객체를 생성합니다.

그 이후, 자식 클래스에서 추가한 필드와 메소드가 객체에 추가됨으로써 child 클래스의 전체 객체가 완성됩니다.

 

따라서 자식 클래스 객체의 내부에는 부모 클래스 객체가 포함돼있으므로 자식 클래스 객체에서 부모 클래스의 멤버를 사용할 수 있는 것입니다.

 

 

 

Do it! 자바 완전 정복을 참고하여 포스팅하였습니다.

LIST