반응형

[Oracle Java Tutorial을 읽고 순서에 의해 정리한 후 본인의 경험과 이해를 바탕으로 작성된 글임을 밝힌다.]

[Java Tutorial, 자바 프로그래밍 기초 배우기, Java Programming, 자바 튜토리얼]

내부 클래스 예제(Inner Class Example)

먼저 배열을 이용한 내부 클래스(inner class) 사용에 대해 아래 예제를 통해 알아본다. 먼저 배열을 생성하고 값을 할당한 뒤 짝수 인덱스를 순서대로 호출하는 프로그램을 만들어 볼 것이다.

DataStructure.java 프로그램은 다음과 같이 구성되어 있다.

  • 외부 클래스(Outer Class)DataStructure는 연 이은 integer값인 0,1,2,3 등을 배열에 할당하는 객체를 생성하는 생성자를 포함하고 있다.

  • 내부 클래스(Inner Class)EvenIteratorIterator인터페이스를 확장(extends) DataStructureIterator인터페이스를 구현(implements)하고 있다. Iterators는 데이터 구조를 단계별로 수행하고 마지막 요소를 체크하거나 현재 값을 가져오거나 다음 값으로 이동하는 전형적인 메서드가 있다.

  • DataStructure 객체를 인스턴스 하는 main메서드는 짝수 인덱스 값을 가진 arrayOfInts 배열을 출력하는 printEven메서드를 호출한다.

 

   public class DataStructure {

 

    private final static int SIZE = 15;

    private int[] arrayOfInts = new int[SIZE];

 

    public DataStructure() {

       for (int i = 0; i < SIZE ; i++) {

          arrayOfInts[i] = i;

          }

    }

 

    public void printEven() {

       DataStructureIterator iterator = this.new EvenIterator();

       while(iterator.hasNext()) {

          System.out.println(iterator.next() + " ");

       }

       System.out.println();

    }

    interface DataStructureIterator extends java.util.Iterator{ }

 

    private class EvenIterator implements DataStructureIterator {

       private int nextIndex = 0;

       public boolean hasNext() {

          return (nextIndex <= SIZE - 1);

       }

 

    public Integer next() {

       Integer retValue = Integer.valueOf(arrayOfInts[nextIndex]);

       nextIndex += 2;

       return retValue;

      }

   }

   public static void main(String[] args) { 

      DataStructure ds = new DataStructure();

      ds.printEven();

   }

}

 

결과는 0, 2, 4, 6, 8, 10, 12, 14

주목해 보면 EvenIterator클래스는 DataStructure 객체의 인스턴스 변수인 arrayOfInts 직접 참조한다.

예제에서 보여준 것처럼 헬퍼 클래스로 구현하기 위해 내부 클래스를 사용할 있다. 사용자 인터페이스의 이벤트들을 다룰 있고 물론 내부 클래스를 어떻게 사용해야 하는지 반드시 알아야 하는 것이다. 왜냐하면 이벤트 핸들링 기술은 그것들을 광범위하게 사용할 있다.

 

 

로컬 및 익명 클래스(Local and Anonymous Classes)

 

내부 클래스에는 2가지 타입이 더 있다. 메서드의 몸체 내에 내부 클래스를 선언할 수 있다. 이 클래스들은 지역 클래스로 알려져 있다. 또한 클래스의 이름 없이 메서드의 몸체 내에 내부 클래스를 선언할 수도 있다. 이 클래스들을 익명 클래스라고 한다.

수식어/한정어(Modifiers)

외부 클래스의 다른 멤버 클래스를 위해 사용하는 내부 클래스를 위한 같은 수식어를 사용할 수 있다. 예를 들어, 다른 클래스 멤버들의 제한적 접근을 위해 사용할 수 있는 것처럼 내부 클래스의 접속을 제한하기 위해 접근 제어자인 private, public 그리고 protected를 사용할 수 있다.

반응형
반응형

[Oracle Java Tutorial을 읽고 순서에 의해 정리한 후 본인의 경험과 이해를 바탕으로 작성된 글임을 밝힌다.]

[Java Tutorial, 자바 프로그래밍 기초 배우기, Java Programming, 자바 튜토리얼]

중첩 클래스(Nested Classes)

자바 프로그래밍 언어(The Java programming language)는 클래스 내에 다른 클래스를 선언할 수 있게 허용한다. 그 클래스를 중첩 클래스(nested라고 부른다.

     class OuterClass {

           ...

           class NestedClass {

                ...

           }

     }

 

중첩클래스(Nested Class)는 두 가지로 구분된다. static과 비static이다. static로 정의된 중첩 클래스는 static중첩 클래스라고 하고 비 static클래스는 inner클래스라고 한다.

     class OuterClass {

          ...

          static class StaticNestedClass {

               ...

         }

        class InnerClass {

              ...

        }

    }

 

중첩 클래스는 포함하는 클래스의 멤버이다. inner클래스(non-static)private로 선언 되었다 해도 포함하는 클래스의 다른 멤버들을 접속한다. static중첩클래스는 포함하는 클래스의 다른 멤버들을 접속하지 않는다. OuterClass의 멤버로서 중첩 클래스는 private, public, protected 또는 package private로 선언될 수 있다. Outer 클래스는 오직 public 또는 package private로만 선언할 수 있음을 기억하자.

중첩클래스는 왜 사용하는가? (Why Use Nested Classes?)

중첩클래스를 사용하는 핵심 이유를 확인해 본다.

  • 오직 한 위치에서만 사용할 수 있는 논리 그룹 클래스의 한 방법이다. : 만약 클래스가 단지 다른 하나의 클래스에만 유용하다면 그 클래스 내에 내장되고 두 개가 함께 있는 것이 논리적이다. 도와주는 클래스 같은 중첩하는 것은 그 패키지를 좀 더 능률적으로 구성한다.

  • 캡슐화를 늘린다. : B는 priavte로 선언될 수밖에 없는 A의 멤버들에 접속이 필요한 클래스로 A와 B 두 개의 상위 클래스를 고려해 보자. 클래스 A 내의 숨겨진 클래스 B로 A의 멤버들은 private로 선언될 수 있고 B는 그 멤버들을 접속할 수 있다. 게다가 B자신은 외부로부터 숨겨질 수 있다.

  • 좀 더 읽기 쉽고 유지하기 좋은 코드를 만든다 : 상위 클래스 내의 작은 클래스로 중첩되는 것은 좀 더 가까운 곳에 사용할 코드를 위치할 수 있다.

 

static 중첩클래스(Static Nested Classes)

클래스 메서드와 변수들로 static중첩 클래스는 그것의 outer클래스와 연관되어 있다. 그리고 static클래스 메서드처럼 static중첩 클래스는 해당 클래스 내 정의된 인스턴스 변수 또는 메서드에 직접 참조할 수 없다. 오직 객체 참조를 통해서만 사용할 수 있다.

staic중첩클래스는 어떤 다른 최상위 클래스 같은 그것의 outer클래스의 인스턴스 멤버들과 상호작용한다. 실제로, static중첩클래스는 동작상 패키징 편의를 위한 또 다른 최상위 클래스에 중첩된 최상위 클래스이다.

Static 중첩클래스는 감싸는 클래스명을 사용해서 접속된다.

OuterClass.StaticNestedClass

예를 들어 static중첩 클래스의 객체를 생성하는 것은 아래와 같다.

OuterClass.StaticNestedClass nestedObject = new OuterClass.StaticNestedClass();

 

 

innser클래스(Inner Classes)

인스턴스 메서드와 변수들로 inner클래스는 그것을 감싼 클래스의 인스턴스와 연관되어 있고 그 객체의 메서드와 필드에 직접 접속한다. 또한 내부 클래스는 인스턴스와 연관되어 있기 때문에 어떤 static멤버 그 자체로 정의될 수 없다.

내부 클래스의 인스턴스인 객체는 외부 클래스의 인스턴스 내에 존재한다. 아래 클래스를 고려해 보자.

     class OuterClass {

         ...

          class InnerClass {

              ...

          }

    } 

 

InnerClass의 인스턴스는 OuterClass의 인스턴스 내에만 존재할 수 있고 그것의 감싸진 인스턴스의 메서드와 필드에 바로 접근할 수 있다. 내부 클래스에 인스턴스 하기 위해 먼저 외부 클래스의 인스턴스가 우선되어야 한다. 그리고 난 후, 아래 구문처럼 외부 객체 내의 내부 객체를 생성한다.

OuterClass.InnerClass innerObject = outerObject.new InnerClass();

쉐도잉(Shadowing)

만약 외부 클래스의 변수명과 내부 클래스의 변수명 그리고 내부 클래스 내의 메서드 파라미터의 명이 (물론 타입도) 같은 경우 접근 하는 방법에 대한 예제이다.

      public class ShadowTest {

           public int x = 0;

           class FirstLevel {

                 public int x = 1;

                 void methodInFirstLevel(int x) {

                         System.out.println("x = " + x);

                         System.out.println("this.x = " + this.x);

                         System.out.println("ShadowTest.this.x = " + ShadowTest.this.x);

                 }

            }

           public static void main(String... args) {

                  ShadowTest st = new ShadowTest();

                  ShadowTest.FirstLevel fl = st.new FirstLevel();

                  fl.methodInFirstLevel(23);

           }

     }

실행결과 :

x = 23

this.x = 1

ShadowTest.this.x = 0

 

내부 클래스의 파라미터에 23 값을 넣으면 파라미터의 값은 23이 된다. 하지만 this를 붙여서 해당 내부 클래스의 x값을 확인하면 23이 아닌 내부 클래스의 x1이 출력된다. 그럼 내부 클래스를 감싸고 있는 외부 클래스에 선언된 같은 이름의 x를 호출하는 방법은 다음과 같다.

ShadowTest.this.x

외부 클래스 명의 this를 사용해서 x값을 호출할 수 있는 것이다.

사실 튜토리얼 기반으로 설명을 해서 이해가 난해할 수도 있을 것이다. 일반적인 프로젝트에서 내부 클래스를 거의 사용하지 않기에 참고로 확인만 하고 추후 더 자세히 예를 들어 포스팅해보겠다.

반응형