반응형

이너 클래스(내부 클래스)

이너 클래스란?

1. 내부 클래스(inner class)란 하나의 클래스 내부에 선언된 또 다른 클래스를 의미합니다. 이러한 내부 클래스는 외부 클래스(outer class)에 대해 두 개의 클래스가 서로 긴밀한 관계를 맺고 있을 때 선언할 수 있습니다.

 

※ 일반적인 클래스

class A{		 		
	…			
}				
class B{				
	…	      // A를 사용하기 위해서는		
}		      // A의 객체를 생성해야한다.

※ 내부 클래스가 포함된 형태

class A{			// B의 외부 클래스
	…		
    class B{		// 내부 클래스
    // 객체생성 없이도 A의 멤버접근가능
    	…	
    }		
	…		
}

2. 내부클래스의 장점

  • 내부 클래스에서 외부 클래스의 멤버들을 쉽게 접근할 수 있다.
  • 코드의 복잡성을 줄일 수 있다. (캡슐화)

이너 클래스의 특징

1. 외부 클래스의 인스턴스를 먼저 생성해야 인스턴스 클래스의 인스턴스를 생성가능하다

    ① class B에서 class A의 객체를 생성해야 사용 가능

    ② class A의 객체를 만들지 않아도 class B에서 class A의 객체를 쓸 수 있다.

    ③ BBB클래스에서 b객체를 사용하려면 또 AAA클래스에서 b객체를 만들어야 한다.

    ④ BBB클래스는 AAA안에서만 사용한다는 가정하에 inner class로 선언한 것

// Ex1)
class AAA{								
    int i = 100;							
    BBB b = new BBB();							
}								
								
class BBB{								
    void method(){							
        AAA a = new AAA();	        // ①
        System.out.println(a.i);	// ①
    }							
}								
								
class CCC{								
    BBB b = new BBB();							
}								
								
public class InnerTest{								
    public static void main(String args[]){							
        BBB b = new BBB();						
        b.method();						
    }							
}
// Ex2)
class AAA{		// AAA는 BBB의 외부 클래스
    int i = 100;
    BBB b = new BBB();		// ③

    class BBB{		// BBB는 AAA의 내부 클래스
        void method(){
            AAA a = new AAA();
            System.out.println(a.i);
        }
    }
}

// BBB클래스가 내부 클래스로 선언 되었기 때문에 에러 발생
class CCC{
    BBB b = new BBB();
}

// BBB클래스가 내부 클래스로 선언 되었기 때문에 에러 발생
public class InnerTest{
    public static void main(String args[]){
        BBB b = new BBB();
        b.method();
    }							
}
// Ex3)
class AAA{                               // AAA는 BBB의 외부 클래스
    int i = 100;
    BBB b = new BBB();                   //    ③

    // BBB는 AAA의 내부 클래스
    class BBB{                           //    ④
        void method(){                   //    ④
//            AAA a = new AAA();                   //    ④
//            System.out.println(a.i);             //    ④
// 객체 생성없이 외부 클래스의 멤버 접근가능          //    ④
            System.out.println(i);       //    ②④
        }                                //    ④
    }                                    //    ④
}

// BBB클래스가 내부 클래스가 되었기 때문에 CCC 에러 발생
class CCC{
    BBB b = new BBB();
}

// BBB클래스가 내부 클래스가 되었기 때문에 에러 발생
public class InnerTest{
    public static void main(String args[]){
        BBB b = new BBB();
        b.method();
    }
}
// 여기서 main에서 내부클래스의 BBB 객체는 생성할수 없다.
// 내부클래스는 외부클래스를 먼저 생성한 다음에야 생성이 가능하기 때문
// BBB클래스는 AAA의 멤버처럼 다루어 진다.

이너 클래스의 종류와 특징

이너 클래스의 종류와 유효범위(scope)는 변수와 동일

// 변수인 경우
class Outer{
    int iv = 0;                // ①
    static int cv = 0;        // ②
            
    void myMethod(){
        int lv = 0;            // ③
    }
}
//내부 클래스인 경우
class Outer{
    class InstanceInner{ … }          // ①
    static class StaticInner{ … }    // ②
            
    void myMethod(){        
        class LocalInner{ ... }        // ③
    }
}
이너 클래스 특징
인스턴스 클래스 (instance class) ① 외부클래스의 멤버변수 선언위치에 선언하며, 외부 클래스의 인스턴스멤버처럼 다루어진다. 주로 외부 클래스의 인스턴스멤버들과 관련된 작업에 사용될 목적으로 선언된다.
인스턴스 클래스 (instance class) ② 외부 클래스의 멤버변수 선언위치에 선언하며, 외부클래스의 static멤버처럼 다루어진다. 주로 외부 클래스의 static멤버, 특히 static메서드에서 사용될 목적으로 선언된다.
인스턴스 클래스 (instance class) ③ 외부 클래스의 메서드나 초기화블럭 안에 선언하며, 선언된 영역 내부에서만 사용될 수 있다.
익명 클래스 (anonymous class) 클래스의 선언과 객체의 생성을 동시에 하는 이름없는 클래스(일회용)

이너 클래스의 제어자와 접근성

이너 클래스의 제어자는 변수에 사용 가능한 제어자와 동일

※ 원래 클래스의 접근제어자(modifier)에는 default와 public 밖에 안됐는데 이너 클래스의 접근제어자에는

public, default, private, protected 모두 사용가능

static 멤버란

    객체 생성 없이 사용가능 한 것

    이너 클래스를 작성하는데 static 멤버가 필요하다면?

    이너 클래스도 static 이너 클래스가 되어야 한다.

// Ex4)
/* 다른 class는 객체를 만들어야만 변수를 사용하는데 그 class안에 static변수가 
// 존재하는건 불가능하다
*/
class Ex7_12 { 
    // static클래스 이외에서는 static변수를 선언할수 없다
    // final static은 상수이므로 허용
    class InstanceInner {
        int iv = 100;
//      static int cv = 100;
        final static int CONST = 100;
    }

// static클래스만 static멤버를 정의할 수 있다.
// static class 안에서만 static int cv 같은 변수를 만들 수 있다.
    static class StaticInner{
        int iv = 200;
        static int cv = 200;
    }

    // static클래스 이외에서는 static변수를 선언할수 없다
    // final static은 상수이므로 허용
    void myMethod(){
        class LocalInner{
            int iv = 300;
//          static int cv = 300;
            final static int CONST = 300;
        }
    }
}

※ static 내부 클래스에서는 외부 클래스의 인스턴스 멤버에 접근할 수 없다.

※ 다만 상수(final)인 경우에는 이너 클래스가 static 멤버를 가질 수 있다.

상수(상수≠변수)인 경우에는 inner class가 static 멤버를 가질수 있다.

※ 지역 내부 클래스는 메서드 내에서만 접근 가능하다.

method()안의 LocalInner class는 그 method() 안에서만 접근 가능하다.
// Ex5)
// Ex4) 이어서

public static void main(String args[]){
    System.out.println(InstanceInner.CONST);    // 가능
    System.out.println(StaticInner.cv); // 가능
    System.out.println(LocalInner.CONST); // 에러 지역 내부 클래스는 메서드 내에서만
}
// Ex6) 내부 클래스의 제어자와 접근성 예제

class Ex7_13 {
    class InstanceInner{ …. }
    static class StaticInner{ …. }

    InstanceInner iv = new InstanceInner(); // instance 멤버끼리는 직접 접근 가능
    static StaticInner cv = new StaticInner(); // static 멤버끼리는 직접 접근 가능
        
    static void staticMethod(){    // static멤버는 instance멤버에 직접 접근 불가
//      InstanceInner obj1 = new InstanceInner();
        static StaticInner cv = new StaticInner();

        // instance 클래스는 외부 클래스를 먼저 생성해야 생성가능
        Ex7_13 outer = new Ex7_13();
        InstanceInner obj1 = outer.new InstanceInner();
    }

    // instance메서드에서는 instance멤버와 static멤버 모두 접근 가능
    void instanceMethod(){
        InstanceInner obj1 = new InstanceInner();
        static StaticInner cv = new StaticInner();
        // 지역 내부 클래스는 외부에서 접근할 수 없다.
        //localInner lv = new LocalInner();
    }

    void myMethod(){
        class LocalInner{ …. }
        LocalInner lv = new LocalInner();
    }
}
// Ex7) 내부 클래스의 제어자와 접근성 예제

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

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

    static class StaticInner {
//  static 클래스는 외부 클래스의 instance 멤버에 접근할 수 없다.
//    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;        // 에러
            int liv4 = LV;        // Ok
        }
    }
}

※ 내부 클래스에서 private 멤버를 이용할 수 있다.

  • private는 원래 다른 클래스에서는 사용할 수 없다.
  • static 클래스 내에서는 여전히 안된다. instance 멤버이기 때문이다

※ 지역 내부 클래스에서는 변수는 이용할 수 없고 상수(final)만 이용할 수 있다.

  • method() 내부의 변수는 지역변수이므로 method() 종료와 함께 소멸된다. method()는 한번 호출되면 종료와 함께 끝나기 때문이다.
  • 내부 클래스의 객체가 더 오래 존재할 수 있다. 누구보다? 지역변수보다 method()가 종료되어도 상수니까 사용할 수 있다.
  • 하지만 JDK1.8부터는 변수의 값을 설정하고 바꾸지만 않으면 에러가 나지 않는다.그래도 그냥 왠만하면 붙이는 것이 좋다.

외부 클래스와 내부 클래스의 변수 구분하기

class Outer3{        
    int value = 10;        //Outer3.this.value    
        
    class Inner{    
        int value = 20;        //this.value
        
        void method1(){
            int value = 30;        // value
            System.out.println("            value:" + value);
            System.out.println("       this.value:" + this.value);
            System.out.println("Outer3.this.value:" + Outer3.this.value);
        }
    }    
}        
        
class Ex7_16{        
    public static void main(String args[]){    
        Outer3 outer = new Outer3();
        Outer3.Inner inner = outer.new Inner();
        inner.method1();
    }
}

[참고 자료]

[자바의 정석 - 기초편] ch7-42~44 내부클래스의 종류, 특징, 선언

[자바의 정석 - 기초편] ch7-45~50 내부클래스의 제어자와 접근성

반응형

+ Recent posts