반응형

[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값을 호출할 수 있는 것이다.

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

반응형
반응형

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

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

필드 초기화 (Initializing Fields)

필드를 선언할 때 초기값을 설정할 수 있는 것은 이미 알고 있을 것이다.

      public class TestClass {

           public static int a = 10; //10으로 초기화

           private Boolean b = false; //false로 초기화

      }

단 한 줄에 선언 및 초기화를 할 수 있고 잘 작동한다. 그러나 한 줄 선언과 초기화는 너무 간단해서 제약이 있다. 에러 핸들링이나 for순환문을 이용한 복합 배열 선언 시엔 부적절한 것이다. 인스턴스 변수는 오류 처리나 다른 로직을 사용할 수 있는 생성자에서 초기화될 수 있다. 클래스 변수를 위한 같은 기능을 자바 프로그래밍 언어에서 제공하는데 바로 static 초기화 블록이다.

비록 클래스 시작부분에 필드를 초기화하는 게 일반적이긴 하지만 꼭 그럴 필요는 없다. 그냥 필드가 사용하기 전에만 선언과 초기화를 하면 된다.

static초기화 블록(static Initialization Blocks)

static초기화 블록은 중괄호 { }를 사용한다. 그리고 중괄호 앞에 “static:” 키워드를 두면 된다.

     static {

           초기화 할 코드를 여기에 구현

     }

클래스는 static초기화 구문을 얼마든지 가질 수 있다. 그리고 클래스 어디서든 구현할 수 있다. 런타임 시스템은 static 초기화 블록이 나타나는 순서대로 호출되는 것을 보장한다.

static블록의 대안으로 전용 static메서드를 사용할 수 있다.

     class Test {

           public static Type myVar = initClassVar();

           private static Type initClassVar() {

                ////초기화할 코드를 여기에 구현

          }

      }

이 방식의 장점은 클래스 변수를 다시 초기화하고 싶을 때 재사용할 수 있다는 것이다.

인스턴스 멤버 초기화 (Initializing Instance Members)

보통은 인스턴스 변수는 생성자 안에서 초기화 한다. 생성자에서 초기화하는 방법을 대신할 2가지 방법이 있다. 초기화 블록과 final메서드이다.

 

 

인스턴스 변수를 위한 초기화 블록(Initializer blocks)static초기화 블록과 비슷하다. 물론 static 키워드는 없다.

{

//초기화 할 코드를 넣는다

}

자바 컴파일러는 모든 생성자에 초기화 블록을 복사한다. 따라서 이 처리방법은 생성자들 간에 코드 블록을 공유하기 위해 사용되어진다.

Final 메서드는 서브클래스에서 오버라이드 될 수 없다. 이 부분은 인터페이스와 상속에서 더 자세히 설명하겠다. 아래는 final메서드 예제이다.

      class Test {

           private Type myVar = initInstVar();

          protected final Type initI:nstVar() {

               //초기화 코드 작성

         }

     }

만약 서브클래스가 초기화 메서드를 재사용하기를 원할 때 특히 유용하다. 메서드가 final인 이유는 인스턴스 초기화 중에 비final 메서드 호출하면 문제가 발생할 수 있기 때문이다.

반응형