2. 타입(Type)과 클래스(Class)
1. 키워드
- 타입(Type)과 클래스(Class)
- 상속(Inheritance)과 다형성(Polymorphism)
2. 타입(Type)과 클래스(Class)
1) 타입과 클래스
- 다음의 예제는
Parent
클래스와 그 클래스를 인스턴스화 하는 예제이다.
class Parent {}
class Test {
public static void main(String[] args) {
① Parent pa;
② pa = new Parent();
}
}
- ①번 라인을 보면, 참조 변수
pa
를 Parent
타입으로 선언만 한 것이다.
- 이 과정에서 참조 변수
pa
는 지역 변수이므로 스택 메모리 상에 위치하게 되며, 초기화되지 않았으므로 null
값이 들어가 있다.
- 즉, 스택 메모리 상에 존재하지만, 해당 참조 변수가 가리키는 메모리 주소의 위치는 아직 정해지지 않은 것이다.
- ②번 라인을 보면,
Parent
클래스의 인스턴스를 참조 변수 pa
에 대입한 것이다.
- 이 과정에서
new
키워드로 인해 Parent
클래스의 인스턴스는 힙 메모리 상에 위치하게 되며, 해당 인스턴스의 메모리 주소는 참조 변수 pa
에 할당된다.
- 즉, 참조 변수
pa
가 가리키는 메모리 주소의 위치가 힙 메모리 상의 Parent
클래스의 인스턴스의 메모리 주소가 된 것이다.
- 이후 참조 변수
pa
를 호출하면, 참조 변수 pa
가 가리키는 힙 메모리 주소로 이동하게 되고, 해당 힙 메모리 주소에 기록된 정보를 해석하여 프로그램이 동작하게 된다.
- 이때 참조 변수
pa
가 해석할 수 있는 범위는 처음 선언했을 때의 타입인 Parent
타입에 의해 정해지게 되는 것인데, 만약 메모리 상에 기록되어 있는 어떠한 정보가 해석될 수 없는 타입으로 되어 있다면, 프로그램은 오작동할 것이므로 컴파일 시 오류를 발생시키는 것이 당연하다.
2) 상속(Inheritance)을 이용한 타입과 클래스의 관계
- 다음의 예제는 상속을 이용하여 타입과 클래스의 관계를 나타내는 예제이다.
class Parent {
void display() {
System.out.println("부모 클래스의 display() 메소드입니다.");
}
}
class Child extends Parent {
void display() {
System.out.println("자식 클래스의 display() 메소드입니다.");
}
void show() {
System.out.println("자식 클래스의 show() 메소드입니다.");
}
}
class Test {
public static void main(String[] args) {
① Parent pa = new Parent();
② pa.display(); // 부모 클래스의 display() 메소드입니다.
③ Child ch = new Child();
④ ch.display(); // 자식 클래스의 display() 메소드입니다.
⑤ ch.show(); // 자식 클래스의 show() 메소드입니다.
⑥ Parent pc = new Child();
⑦ pc.display(); // 자식 클래스의 display() 메소드입니다.
⑧ pc.show(); // 컴파일 오류 발생
⑨ Child cp = new Parent(); // 컴파일 오류 발생
⑩ cp.display(); // 컴파일 오류 발생
}
}
- ①번부터 ⑤번 라인까지는 설명하지 않아도 이제 이해가 될 것이지만, ⑥번부터 ⑩번 라인까지는 이해하기 힘들 것이다.
- ⑥번 라인을 보면
Parent
타입으로 참조 변수 pc
를 선언한 후, Child
클래스의 인스턴스를 대입한 것이다.
- 위에서 설명했듯이, 이런 경우 참조 변수
pc
가 해석할 수 있는 범위는 Parent
타입으로 정해지게 된다.
- ⑦번과 ⑧번 라인을 보면 오버라이딩 된
Child
클래스의 display()
메소드는 잘 호출되지만, show()
메소드를 호출하는 경우 컴파일 오류가 발생하게 된다.
- 그 이유는 참조 변수
pc
가 해석할 수 있는 범위인 Parent
클래스에는 display()
메소드만 존재하기 때문인데, Parent
클래스를 상속받은 Child
클래스에 display()
와 show()
메소드가 있다고 하더라도 Child
클래스의 display()
메소드만 해석할 수 있게 되는 것이다.
- ⑨번 라인을 보면
Child
타입으로 참조 변수 cp
를 선언한 후, Parent
클래스의 인스턴스를 대입한 것이다.
- 이때 컴파일 오류가 발생하게 되는데, 그 이유는
Child
타입으로 선언된 참조 변수 cp
가 사용할 수 있는 멤버의 개수가 Parent
클래스의 인스턴스의 멤버의 개수보다 많기 때문이다.
- 위의 예제의
Child
클래스에는 display()
와 show()
메소드가 존재하고, Parent
클래스에는 display()
메소드가 존재하므로 Child
클래스의 멤버의 개수가 더 많다.
- 이는 다형성(Polymorphism)을 구현하는 데에 있어서 제약 조건이라고 할 수 있는데, 항상 참조 변수가 사용할 수 있는 멤버의 개수가 실제 인스턴스의 멤버의 개수보다 같거나 적어야 참조할 수 있다.