본문 바로가기

자바 웹 개발자가 될거야/JAVA

[JAVA] 중첩클래스 / 인스턴스 멤버 클래스 / 정적 멤버 클래스 / 로컬 클래스 / 중첩클래스 참조

< 중첩 클래스 >

 

① 분류

 

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

- 멤버 Inner 클래스 : 쿨래스의 멤버로서 선언되는 중첩 클래스

  로컬 Inner 클래스 : 생성자 또는 메소드 내부에서 선언되는 중첩 클래스

 

 

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

 

- 바이트 코드 파일 이름

  · 멤버 클래스 : 바깥클래스 $ 멤버 클래스.class

  · 로컬 클래스 : 바깥클래스 $1 로컬 클래스.class

 

 

② 인스턴스 멤버 클래스

 

- static 키워드 없이 중첩 선언된 클래스

- 정적필드와 메소드 선언할 수 없다

 

class A {
	class B {
    	B(){} // 생성자
        int field1; // 인스턴스 필드
        // static int field2; 정적 필드 불가능
        
        void method1(){} // 인스턴스 메소드
        // static void method2(){} 정적 메소드 불가능
    }
}

 

 

- 바깥 클래스 외부에서 이너 클래스 객체를 생성하려면 먼저 바깥 클래스 객체를 생성하고 이너 클래스 객체 생성해야 한다

  (일반적으로 바깥 클래스 외부에서 이너 클래스 객체를 생성하는 일은 거의 없다.)

 

A a = new A();  // 바깥 클래스 객체 먼저 생성
A.B b = a.new B();
b.field1 = 3;
b.method1();

class A{
    class B { ... }

    void methodA(){
        B b = new B();
        b.field = 3;
        b.method1();
    }
}

 

 

 

③ 정적 멤버 클래스

 

- static 키워드로 선언된 클래스

- 모든 종류의 필드와 메소드 선언 가능

 

class A {
	class C {
    	C(){} // 생성자
        int field1; // 인스턴스 필드
        static int field2; 정적 필드         
        void method1(){} // 인스턴스 메소드
        static void method2(){} 정적 메소드
    }
}

 

 

- 바깥 클래스 외부에서 정적 멤버 클래스 객체를 생성하기 위해서는 바깥 클래스 객체를 생성할 필요 없다

 

A.C c = new A.C();
c.field1 = 3;
c.method1();
A.C.field2 = 3;
A.C.method2();

 

 

 

④ 로컬 클래스

 

- 메소드 내에서 선언된 클래스

- 접근제한자 ( public, private ) 및 static 붙일 수 없다

 

void method(){
	class D{
    	D(){ }
        int field1;
        // static int field2;
        void method1() { }
        // static void method2() { }
    }
    D d = new D();
    d.field1 = 3;
    d.method1();
}

 

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

 

 

 

 

⑤ 멤버 클래스에서 사용 제한

 

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

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

 

 

class A {
    int field1;
    void method1(){...}

    static int field2;
    static void method2() { ... }

    class B {
        void method(){
            field1 = 10;
            method1();

            field2 = 10;
            method2();
        }
    }
}

 

class A {
    int field1;
    void method1(){...}

    static int field2;
    static void method2() { ... }

    static class C {
        void method(){
            // field1 = 10; 불가능
            // method1(); 불가능

            field2 = 10;
            method2();
        }
    }
}

 

 

⑥ 로컬 클래스에서 사용 제한

 

public class Outer {
	
	// 자바 7이전
	public void method1(final int arg) {
		final int localVariable = 1;
		// final 상수 변경할 수 없다
		// arg = 100;
		// localVariable = 100;
		
		class Inner{
			public void method() {
				int result = arg + localVariable;
			}
		}
	}
	
	// 자바 8 이후
	public void method2(int arg) {
		int localVariable= 1;
		// final이 생략되어 있어도 값 변경 못함
		// arg = 100;
		// localVariable = 100;
		class Inner{
			public void method() {
				int result = arg + localVariable;
			}
		}
	}

}

 

- method() 안에서 선언된 지역변수는 상수인 경우에만 사용가능하다

 

public class Outer {
	
	public void method1(final int arg) {

        int a = 200;
		
		class Inner{
			public void method() {
				a = a + 100; // method의 지역변수 사용불가능
			}
		}
	}
}

 

- 자바 8버전 이후에는 final이 생략되어도 상수로 생각하고 이너클래스에서 사용가능하다

   단, final이 생략되었다고 해서 그냥 변수가 아니기 때문에 값 변경은 여전히 안된다

 

 

 

⑦ 중첩 클래스에서 바깥 클래스 참조 얻기

 

- 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 OutterExample {

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

	}
}

 

 

- field 변수가 동일이름으로 2개로 선언되어있지만 this 키워드를 사용하여 참조를 구분한다

- 중첩 클래스에서 this 키워드 사용하면 중첩 클래스 객체 참조( 더 가까운 것 )가 우선순위가 높다

- 바깥 클래스에 접근하기 위해선 '바깥 클래스.this'를 사용해준다