2011년 5월 10일 화요일

자바의 비정적 내부클래스(Inner classes)


오늘은 중첩클래스의 가장 일반적인 형태인 자바의 비정적 내부클래스(Inner classes)에 대해서 살펴보기로 하자. 용어부터 정리하자면,

비정적 내부클래스
=Non-static nested classes
=Inner classes
=일반 내부클래스
=멤버클래스

다 같은 말이고 보통 내부클래스를 얘기할때 비정적 내부클래스를 칭한다. 멤버랑 같은 위치에 있다고 하여 멤버클래스라고도 불리는 비정적 내부클래스(여기서는 그냥 내부클래스라고 표기하겠다)를 자바에서는 아래처럼 작성하는데 이해를 돕기 위해 예제를 보자.

class Outer
{
      ...
      class Inner
      {
         ...
      }
}

내부클래스인 Inner 클래스는 외부클래스인 Outer의 멤버들과 같은 위치에 존재하며 외부클래스의 메소드와 필드 모든 요소들에 대해서 외부클래스처럼 바로 접근해서 쓸수 있다. 내부클래스도 클래스이므로 public이나 private 같은 접근지정자를 쓸수 있다. 내부클래스는 객체를 생성하는 방법이 다르니 지금부터 집중하기 바란다. 말그대로 내부클래스는 외부클래스의 내부에 있으므로 혼자서 독단적(?)으로 객체생성이 불가능하고 외부클래스의 객체를 이용해서 내부클래스의 객체를 생성할수 있다.

Outer.Inner oi = new Outer( ).new Inner( );

Outer o = new Outer( );
Outer.Inner oi = o.new Inner( );

내부클래스의 객체를 생성하는 방식인데 두가지 중 아무거나 써도 되지만 나중에 힘을 조금이라도 아낄려면 후자를 쓰는게 좋다. 첫번째 방식은 내부클래스 요소에만 쓸수 있는 객체이나 두번째 방식은 외부랑 내부 객체 모두를 만들어놨으므로 전자와는 다르게 외부 객체가 필요할때도 다시 만들 필요없이 사용가능하니 일석이조가 아니겠는가?

자바는 각 클래스마다 컴파일후에 .class라는 파일을 생성한다. 그럼 내부클래스는 어떻게 될까? 위의 클래스 이름을 예로 들자면 외부에 Outer 클래스가 내부에는 Inner 클래스가 위치하고 있다면 컴파일후 생성되는 파일은 Outer$Inner.class 로 된다. 따라서 생성된 자바파일을 볼때 달러표시가 있으면 내부클래스를 썼구나라고 짐작할수 있다.

그럼 내부클래스(Inner)안에 또 내부클래스(InnerInner)를 만들수 있을까? 직접 해보자.ㅎㅎ 가능하다. 그럴경우 생성되는 파일은 어떻게 될까? Outer$Inner$InnerInner.class 로 생성된다. 어떤 식으로 파일이 생성되는지 이해가 이제 될것이다. 그렇다면 Outer 클래스안에 내부클래스 Inner2 라는게 하나 더 있다면? 당연히 Outer$Inner2.class 가 만들어진다. 이제 우리는 자바의 컴파일된 파일이름만 봐도 내부클래스를 만들었는지 식별할수 있는 고수(?)가 되었다.^^

내부클래스에서는 클래스 필드에 들어가는 상수(static final)를 제외하곤 static을 붙여 멤버들을 사용할수가 없다. 이는 외부클래스의 객체가 있어야만 내부클래스의 멤버를 참조할수 있고 다시 말해서 내부클래스는 자신을 둘러싸고 있는 클래스가 인스턴스화가 되어야 사용가능하므로 위치상 static을 사용하지 못한다. static에 관한 자세한 내용은 저번 강좌를 다시 보기 바란다.

내부클래스는 멤버클래스라고 불리는 것처럼 외부클래스의 멤버들을 자유롭게 불러다 쓸수 있는데 그렇다면 외부클래스는 내부클래스 멤버들을 불러다 쓸수 있을까? 당연히 다른 곳에서 쓰는 것처럼 쓰면 된다. 예제를 보면 알게 될 것이다.

자바에서 같은 변수이름을 구분하기 위해 쓰는 this라는 용법이 있었다. 전역변수와 지역변수를 구분하기 위해서 말이다. 그럼 외부클래스와 내부클래스도 이름이 같은 변수를 쓸수 있을까? 만약 변수 이름이 같다면 어떻게 구별해서 쓸수가 있을까? 내부클래스도 클래스이니 다 가능하고 역시 this 로 구분이 가능하다. 쓰는 방식(외부객체명.this.변수명;)만 조금 알면 된다. 역시 예제를 보면 알게 될 것이다. 예제에 대한 관심을 증폭시키고 있는 중이다. ㅎㅎ

이제 예제를 볼텐데 내부클래스도 일반 클래스와 똑같은 클래스가 안에 하나 더 있다고 생각하기 바란다. 다른게 아니다. 똑같은데 내부클래스이므로 일반 클래스에 비해 위치의 제약이 있으므로 쓰는 방식의 차이가 조금 있을 뿐이다. 주석을 자세히 달았으니 이해하는데 큰 어려움은 없을 것이다. 여기를 누르고 다운받아 실행하기전 결과를 생각해보는 시간을 갖기를 간절히(?) 바란다.^^

I'm 내부클래스 h()
100
600
700
=====강이의 자바강좌=====
I'm 내부클래스 h()
300
I'm 내부클래스 h()
I'm 외부클래스 f()
I'm 외부클래스 static g()

예제의 결과를 출력해 보았다. 오늘 강좌의 내용을 예제에 다 담았다고 해도 과언이 아닐 것이다. 내용을 모르고 예제를 보기만 해도 이해가 퍽퍽 가도록 만들었다. ㅎㅎ 예제를 통해서 당연히 작동됨에도 불구하고 내부클래스에 대한 편견때문에 미처 생각지 못한 기능들을 예제를 통해 재발견(?)하는 시간을 갖게 될것이다. 자 홍보(?)는 충분히 한듯하니 예제보고 마무리 잘하기 바란다.^^

댓글 5개:

  1. My brother recommended I might like this blog. He was
    totally right. This post truly made my day. You cann't imagine simply how much time I had spent for this info! Thanks!

    Also visit my site; natural cellulite treatment

    답글삭제
  2. 강이 잘 보고 있습니다.
    쫄지말고 자바해아지....ㅋㅋ

    답글삭제
  3. 이해가 팍팍됩니다요 =ㅅ=;

    답글삭제
  4. 잘 보고 있습니다. 외부객체.this.변수명이 선뜻 이해가 잘 안됩니다.
    j()메소드에서 this는 Inner의 객체이기 때문에, 예제의 Outer.this.a = Outer.Inner.a 이고 이는 곧 this.a와 같은 결과값을 출력할 것으로 기대되는데... 일견 이해하기가 어렵네요.

    답글삭제