Programming/Java

[Java 자바] 9. 중첩 ① 중첩 클래스

erinh 2022. 8. 9. 20:51
반응형

9-1. 중첩 클래스

- 클래스 내부에 선언한 클래스로 중첩 클래스를 사용할 경우 두 클래스의 멤버를 서로 쉽게 접근할 수 있으며,
  외부에는 불필요한 관계 클래스를 감춤으로써 코드의 복잡성을 줄일 수 있음

- 클래스 내부에 선언되는 위치에 따라 두 가지로 분류

선언 위치에 따른 분류 선언 위치 설명
멤버
클래스
인스턴스
멤버 클래스
class A {
  class B {...}
}
A 객체를 생성해야만 사용할 수 있는 B 중첩 클래스
정적
멤버 클래스
class A {
  static class B {...}
}
A 클래스로 바로 접근할 수 있는 B 중첩 클래스
로컬 클래스 class A {
  void method() {
    class B {...}
  }
}
method()를 실행할 때만
사용할 수 있는 B 중첩 클래스

- 멤버클래스도 하나의 클래스이기 때문에 컴파일시 바이트 코드 파일(.class)이 별도로 생성

A $ B . class

- 로컬 클래스일 경우에는 다음과 같이 $1이 포함된 바이트 코드 파일이 생성됨

A $1 B . class

9-1-1. 인스턴스 멤버 클래스

- 인스턴스 멤버 클래스는 인스턴스 필드, 메소드만 선언 가능 (정적 필드, 메소드 선언 불가)
- A클래스 외부에서 인스턴스 멤버 클래스 B의 객체를 생성하려면 먼저 A의 객체를 생성하고 B 객체를 생성해야 함

public class OuterClass {

  class NestedClass {
		
    NestedClass() {}
		
    int field1;
    void method1() {}
  }
}

public class NestedClassTest {
  public static void main(String[] args) {
    
    OuterClass a = new OuterClass();
    OuterClass.NestedClass b = a.new NestedClass();
    b.field1 = 3;
    b.method1();
  }
}

9-1-2. 정적 멤버 클래스

- 정적 멤버 클래스는 모든 종류의 필드와 메소드 선언 가능
- A클래스 외부에서 정적 멤버 클래스 C의객체 객체를 생성하기 위해서는 별도의 A객체 생성 필요 없이 진행 가능 

public class OuterClass {

  static class StaticNestedClass {
		
    StaticNestedClass() {}
    
    int field1;
    static int field2;
    void method1() {}
    static void method2() {}
  }
}

public class NestedClassTest {
  public static void main(String[] args) {

    OuterClass.StaticNestedClass c = new OuterClass.StaticNestedClass();
    // 일반 필드, 메소드는 객체 생성 후 객체로 호출
    c.field1 = 3;
    c.method1();
    // 정적 필드, 메소드는 클래스명으로 바로 호출
    OuterClass.StaticNestedClass.field2 = 3;
    OuterClass.StaticNestedClass.method2();
  }
}

9-1-3. 로컬 클래스

- 메소드 내부에서 선언하는 중첩 클래스로, 접근제한자 및 static을 쓸 수 없음 (메소드 내부에서만 사용 가능하기 때문)

- 메소드가 실행될 때 메소드 내에서 객체를 생성하고 사용해야 함

public class OuterClass {

  void method() {
    class LocalNestedClass {
      int field1;
      void method1() {}
    }
    
    LocalNestedClass d = new LocalNestedClass();
    d.field1 = 3;
    d.method1();
    System.out.println(d.field1);
  }
}

public class NestedClassTest {
  public static void main(String[] args) {
  
    OuterClass a = new OuterClass();
    a.method();
  }
}

9-2. 중첩 클래스의 접근 제한

9-2-1. 바깥 필드와 메소드에서 사용 제한

1) 인스턴스 멤버 클래스
- 바깥 클래스의 인스턴스 필드의 초기값이나 인스턴스 메소드에서 객체 생성 가능
- 바깥 클래스의 정적 필드의 초기값이나 정적 메소드에서는 객체 생성 불가

2) 정적 멤버 클래스
- 모든 필드의 초기값이나 모든 메소드에서 객체 생성 가능

public class A {

  // 인스턴스 필드
  B field1 = new B();		// (O)
  C field2 = new C();		// (O)
  
  // 인스턴스 메소드
  void method1() {
    B var1 = new B();		// (O)
    C var2 = new C();		// (O)
  }
  
  // 정적 필드 초기화
  // static B field3 = new B();	// (X)
  static C field4 = new C();	// (O)
  
  // 정적 메소드
  static void method2() {
    //B var1 = new B();		// (X)
    C var2 = new C();		// (O)
  }
  
  // 인스턴스 멤버 클래스
  Class B {}
  
  // 정적 멤버 클래스
  static Class C {}
}

9-2-2. 멤버 클래스에서 사용 제한

1) 인스턴스 멤버 클래스
- 인스턴스 멤버 클래스 안에서는 바깥 클래스의 모든 필드와 모든 메소드 접근 가능

2) 정적 멤버 클래스

- 정적 멤버 클래스 안에서는 바깥 클래스의 정적 필드와 정적 메소드에만 접근 가능

public class A {
  int field1;
  void method1() {}
  
  static int field2;
  static void method2() {}
  
  class B {
    void method() {
      field1 = 10;
      method1();
      
      field2 = 10;
      method2();
    }
  }
  
  static class C {
    void method() {
     //field1 = 10;		// 접근 불가
     //method1();		// 접근 불가
     
     field2 = 10;
     method2();
    }
  }
}

9-2-3. 로컬 클래스에서 사용 제한

- 로컬클래스에서 사용되는 매개 변수와 로컬 변수는 모두 final의 특성을 갖게 되며, 값 수정이 불가해짐

public class OuterClass {

  public void method1(int arg) {
    int localVariable = 1;
    //arg = 100;
    //localVariable = 100;
    class Inner {
      public void method() {
        int result = arg + localVariable;
        System.out.println(result);
      }
    }
    
    Inner i = new Inner();
    i.method();
  }
	
  public static void main(String[] args) {
    OuterClass a = new OuterClass();
    a.method1(50);
  }
}

9-2-4. 중첩 클래스에서 바깥 클래스 참조 얻기

- 중첩 클래스에서 this키워드는 중첩 클래스의 객체 참조를 의미
- 중첩 클래스 내부에서 바깥 클래스의 객체 참조를 얻으려면 바깥 클래스 이름을 this 앞에 붙여주면 됨

public class Outter {
  String field = "Outter-field";
  
  void method() {
    System.out.println("Outter-method");
  }
  
  class Nested {
    String field = "Nested-field";
    void method() {
      System.out.println("Nested-method");
    }
    
    void print() {
      // 중첩객체 참조
      System.out.println(this.field);
      this.method();
      
      // 바깥객체 참조
      System.out.println(Outter.this.field);
      Outter.this.method();
    }
  }
}

public class OutterTest {
  public static void main(String[] args) {
    Outter outter = new Outter();
    Outter.Nested nested = outter.new Nested();
    nested.print();
  }
}

 

반응형