2011년 11월 30일 수요일

Java 중첩클래스 내부클래스

Summary of Nested Classes

A class defined within another class is called a nested class. Like other members of a class, a nested class can be declared static or not. A nonstatic nested class is called an inner class. An instance of an inner class can exist only within an instance of its enclosing class and has access to its enclosing class's members even if they are declared private.The following table shows the types of nested classes:
Types of Nested Classes
TypeScopeInner
static nested classmemberno
inner [non-static] classmemberyes
local classlocalyes
anonymous classonly the point where it is definedyes


http://download.oracle.com/javase/tutorial/java/javaOO/summarynested.html



출처 : http://web.lge.cn:8000/system/java/1145

클래스 안에 클래스를 정의할 수도 있는데 이런 클래스를 내부 클래스(Inner Class)라고 한다. 네 종류의 내부 클래스가 있다.
  
 종류
 형태
정적 클래스(Static Calss)
클래스의 멤버로 static 클래스가 있는 경우
멤버 클래스(Member Class)
클래스의 멤버로 클래스가 있는 경우
지역 클래스(Local Class)
메소드 내에 클래스가 있는 경우
익명 클래스(Anonymous Class)
이름이 없는 클래스

정적 클래스(Static Calss)

다음 코드를 보면 클래스 내부에 static 클래스가 존재한다.

class Outer{
  static class Inner{
  }
}

Outer 클래스 안에 Inner 클래스가 있다. 이놈들을 어떻게 해석을 해야할까? Inner는 Outer안에 있으므로 Outer의 멤버라고 생각하자. 근데 Inner는 static 클래스이므로 static 멤버이다. static 멤버는 객체를 만들지 않고도 사용할 수 있으므로 Outer의 객체 없이도 Inner를 참조할 수 있다. 다른 말로 Outer의 객체 없이도 Inner의 객체를 만들 수 있다. Outer 클래스 외부에서 Inner 객체를 만들면 아래와 같다.

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

static 변수를 클래스 외부에서 참조하는 것과 비슷해 보인다.

Outer 클래스 내부에서 Inner 객체를 만들면 아래와 같다.

Inner ob=new Inner();

클래스 내부에서 Inner를 참조하기 때문에 클래스이름을 생략해도 된다.

static 메소드에서 static 변수나 메소드를 참조할 수 있는 것과 같이 static 클래스인 Inner도 Outer의 static 변수나 메소드를 참조할 수 있다. 하지만 일반 멤버는 참조할 수 없다.

class Outer{
  static int a=10;
  int b=20;
  static void f(){...}
  static class Inner{
    void g(){
      int d=a;  // static 변수
      f();       // static 메소드
      // b=100; 일반 멤버는 참조 불가
    }
  }
}

멤버 클래스(Member Class)
멤버 클래스의 모양은 다음과 같다.

class Outer{
  class Inner{
  }
}

Inner가 Outer의 멤버로 정의된 경우이다. 객체를 만들어야만 멤버 변수를 사용할 수 있는 것과 같이, Outer의 객체가 있어야 Inner의 객체를 만들 수 있다.

Outer out=new Outer();       // Outer의 객체
Outer.Inner in=out.new Inner(); // Inner의 객체는 Outer의 객체를 통해서

모양이 이상하다. 하지만 곰곰이 생각해보면 이해될 것이다.

멤버 메소드에서 모든 멤버를 참조할 수 있듯이, Inner 클래스는 Outer의 모든 멤버를 참조할 수 있다.

class Outer{
  static int a=10;
  int b=20;
  static void f(){...}
  void g(){...}
  class Inner{
    void h(){
      int d=a;     // static 변수
      f();         // static 메소드
      b=100;     // 멤버 변수
      g();        // 멤버 메소드
    }
  }
}


지역 클래스(Local Class)
지역 클래스는 지역 변수와 같이 메소드 내부에서 정의된 클래스이다.

void f(){
  class Inner{
  }
}

메 소드 f() 내부에 Inner 클래스가 정의되어 있다. 정말이지 묘한 모양을 하고 있다. 하지만 지역 변수와 같다고 생각하면 된다. 지역 변수는 메소드 내부에서만 사용할 수 있고 메소드의 실행이 끝나면 사라진다. 지역 클래스도 마찬가지로 메소드 내부에서만 객체를 만들 수 있고 메소드의 실행이 끝나면 클래스가 메모리에서 사라진다.

void f(){
  class Inner{                         // x1
    void hi(){
      System.out.println("안뇽~~~");
    }
  }
  Inner in=new Inner();               // x2, 메소드 내부에서 객체를 생성
  in.hi();                               // x3
}                                      // x4

메 소드 f()를 호출하면 x1행에서 Inner 클래스가 정의된다. x2행에서 객체를 만들고 사용한다. x4행에서 메소드 f()의 실행이 종료되면 메소드 내부에서 정의된 모든 것들이 소멸된다. 즉, Inner 클래스와 in의 객체가 메모리에서 제거된다. 메소드를 호출할 때마다 이 같은 과정이 반복된다.

지역 클래스는 자신을 포함하는 클래스(enclosing class)의 모든 멤버를 참조할 수 있다.
지역 클래스는 자신을 포함하는 메소드의 지역 변수나 매개 변수 중에 final만 참조할 수 있다.

익명 클래스(Anonymous Class)
interface로 정의된 Inter가 다음과 같이 정의되어 있다고 가정하자.

interface Inter{
  public void f();
}

Inter를 구현하는 클래스를 만들고자 한다. 그런데 이 클래스로부터 단 하나의 객체가 만들어진다면 다음과 같이 할 수 있다.

Inter ob = new Inter(){★};

★가 있는 자리에 Inter를 구현하면 되는데, '{★}'를 익명 클래스(이름 없는 클래스)라고 한다. 이렇게 클래스를 정의하면 이 클래스는 레퍼런스 변수 ob만 사용할 수 있다.

Inter ob=new Inter(){
  public void f(){
    System.out.println("안녕~~~");
  }
};                                  // 세미콜론을 빼먹지 말자.

위 코드를 가만히 보자. 클래스를 정의하고 객체를 만들지만 마치 객체를 정의하는 것처럼 보인다. 익명 클래스는 오직 하나의 객체를 위해서 정의하는 것이다.

인터페이스뿐만 아니라 클래스를 상속하는 익명 클래스도 만들 수 있다.

class Anony2_1{
  public void hi(){
    System.out.println("hi?");
  }
  public void hello(){
    System.out.println("hello?");
  }
}
public class Anony2{
  public static void main(String[] args){
    Anony2_1 ob=new Anony2_1(){     // Anony2_1을 상속하는 클래스의 객체
      public void hi(){
        System.out.println("안녕?");
      }
    };
    ob.hi();
    ob.hello();
  }
}

댓글 없음:

댓글 쓰기