java 내부클래스

조항주·2022년 5월 12일

study

목록 보기
9/20
post-thumbnail

내부 클래스의 제어자와 접근성

인스턴스클래스와 스태틱 클래스는 외부 클래스와 멤버변수와 같은 위치에 선언되며, 멤버변수와 같은 성질을 갖는다.
내부 클래스도 클래스이기 때문에 abstract나 final과 같은 제어자를 사용할 수 있을 뿐만 아니라, 멤버변수들처럼 private,protected과 접근제어자도 사용이 가능하다.

ex1

내부 클래스 중에서 스태틱 클래스만 static 멤버를 가질 수 있다.
final static이 동시에 붙은 변수는 상수이므로 모든 내부 클래스에서 사용가능하다.

class InnerEx1 {
  class InstanceInnter {
    int iv = 100;
    //static int cv = 100; => 에러
    final static int CONST = 100; // => 허용
  }
  
  static class StaticInner {
    int iv = 200;
    static int cv = 200;
  }
  
  void myMethod() {
    class LocalInner {
      int iv = 300;
      //static int cv = 300; => 에러
      final static int CONST = 300; // => 허용
    }
  }
  
	public static void main(String[] args) {
    System.out.println(InstanceInner.CONST); //100
    System.out.println(StaticInner.cv); // 200
  }
}

ex2

인스턴스 클래스는 외부 클래스의 인스턴스 멤버를 객체생성 없이 바로 사용할 수 있지만, 스태틱 클래스는 외부 클래스의 인스턴스 멤버를 객체생성 없이 사용할 수 없다. 인스턴스 클래스는 스태틱 클래스의 멤버들을 객체생성 없이 사용할 수 있지만, 스태틱 클래스에서는 인스턴스의 멤버들을 객체생성 없이 사용할 수 없다.

package com.company;

class InnerEx2 {
    class InstanceInner {}
    static class StaticInner {}

    // 인스턴스멤버 간에는 서로 직접 접근이 가능하다.
    InstanceInner iv = new InstanceInner();
    // static 멤버 간에는 서로 직접 접근이 가능하다.
    static StaticInner cv = new StaticInner();

    static void staticMethod() {
        // static멤버는 인스턴스멤버에 직접 접근할 수 없다.
//		InstanceInner obj1 = new InstanceInner();
        StaticInner obj2 = new StaticInner();

        //	굳이 접근하려면 아래와 같이 객체를 생성해야 한다.
        //	인스턴스클래스는 외부 클래스를 먼저 생성해야만 생성할 수 있다.
        InnerEx2 outer = new InnerEx2();
        InstanceInner obj1 = outer.new InstanceInner();
    }

    void instanceMethod() {
        // 인스턴스메서드에서는 인스턴스멤버와 static멤버 모두 접근 가능하다.
        InstanceInner obj1 = new InstanceInner();
        StaticInner obj2 = new StaticInner();
        // 메서드 내에 지역적으로 선언된 내부 클래스는 외부에서 접근할 수 없다.
//		LocalInner lv = new LocalInner();
    }

    void myMethod() {
        class LocalInner {}
        LocalInner lv = new LocalInner();
    }
}

ex3

인스턴스 클래스는 외부 클래스의 인스턴스 멤버이기 때문에 인스턴스 멤버와 static 멤버를 모두 사용할 수 있다.
스태틱 클래스는 외부 클래스의 static 멤버이기 때문에 인스턴스 멤버를 사용할 수 없다. 단지 static 멤버만을 사용할 수 있다.
지역 클래스는 외부 클래스의 인스턴스 멤버와 static 멤버를 모두 사용할 수 있으며, 지역 클래스가 포함된 메서드에 정의된 지역변수도 사용할 수 있다. 단, final이 붙은 지역변수만 접근 가능하다.

package com.company;

class InnerEx3 {
    private int outerIv = 0;
    static int outerCv = 0;

    class InstanceInner {
        int iiv  = outerIv;  // 외부 클래스의 private멤버도 접근가능하다.
        int iiv2 = outerCv;
    }

    static class StaticInner {
        // 스태틱 클래스는 외부 클래스의 인스턴스멤버에 접근할 수 없다.
//		int siv = outerIv;
        static int scv = outerCv;
    }

    void myMethod() {
        int lv = 0;
        final int LV = 0;  // JDK1.8부터 final 생략 가능

        class LocalInner {
            int liv = outerIv;
            int liv2 = outerCv;
            //	외부 클래스의 지역변수는 final이 붙은 변수(상수)만 접근가능하다.
			int liv3 = lv;	// 에러!!!(JDK1.8부터 에러 아님)
            int liv4 = LV;	// OK

        }
        
    }

    void method() {

    }
}

메서드가 수행을 마쳐서 지역변수가 소멸된 시점에도, 지역 클래스의 인스턴스가 소멸된 지역변수를 참조하려는 경우가 발생할 수 있기 때문이다.

ex4

외부 클래스가 아닌 다른 클래스에서 내부 클래스를 생성하고 내부 클래스의 멤버에 접근하는 예제이다.

package com.company;

class Outer1 {
    class InstanceInner {
        int iv=100;
    }
    static class StaticInner {
        int iv=200;
        static int cv=300;
    }

    void myMethod() {
        class LocalInner {
            int iv=400;
        }
    }
}

class InnerEx4 {
    public static void main(String[] args) {
        // 인스턴스클래스의 인스턴스를 생성하려면
        // 외부 클래스의 인스턴스를 먼저 생성해야 한다.
        Outer1 oc = new Outer1();
        Outer1.InstanceInner ii = oc.new InstanceInner();

        System.out.println("ii.iv : "+ ii.iv);
        System.out.println("Outer.StaticInner.cv : " + Outer1.StaticInner.cv);

        // 스태틱 내부 클래스의 인스턴스는 외부 클래스를 먼저 생성하지 않아도 된다.
        Outer1.StaticInner si = new Outer1.StaticInner();
        System.out.println("si.iv : "+ si.iv);
    }
}

ex5

내부 클래스와 외부 클래스에 선언된 변수의 이름이 같을 때 변수 앞에 'this' 키워드와 '외부 클래스명.this'를 붙여서 구별할 수 있다.

package com.company;

class Outer2 {
    int value=10;	// Outer.this.value

    class Inner {
        int value=20;	// this.value

        void method1() {
            int value=30;
            System.out.println("           value :" + value);
            System.out.println("      this.value :" + this.value);
            System.out.println("Outer.this.value :" + Outer2.this.value);
        }
    } // Inner클래스의 끝
} // Outer클래스의 끝

class InnerEx5 {
    public static void main(String args[]) {
        Outer2 outer = new Outer2();
        Outer2.Inner inner = outer.new Inner();
        inner.method1();
    }
} // InnerEx5 끝

생각을 해보자

ex1 왜 final static는 허용?

ex3 왜 final이 붙은 지역변수는 사용가능

0개의 댓글