Skip to content

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();
  }
}


  • ①번 라인을 보면, 참조 변수 paParent 타입으로 선언만 한 것이다.
  • 이 과정에서 참조 변수 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)을 구현하는 데에 있어서 제약 조건이라고 할 수 있는데, 항상 참조 변수가 사용할 수 있는 멤버의 개수가 실제 인스턴스의 멤버의 개수보다 같거나 적어야 참조할 수 있다.