-
[Camel][Java] Inner , Local , Anonymous 클래스란?Java/개념 정리 2020. 2. 24. 15:53
Inner 클래스란?
class Outer1 { class Inner { . . . } } class Outer2 { static class Nested { . . . } }
Java에서는 클래스 내부에 다른 클래스를 정의할 수 있습니다. 바깥쪽에 정의된 클래스를 Outer 클래스라고 하고 내부에 정의된 클래스를 Inner 클래스라고 합니다. Inner 클래스의 경우 static으로 선언이 가능하고 이를 가리켜 Static Inner 클래스 또는 Nested 클래스라고 합니다. Nested 클래스는 클래스 내부에 정의되는 클래스이기 때문에 private으로 정의될 경우 외부에서 인스턴스 생성이 불가능하게 됩니다.
Inner 클래스의 특징
Inner 클래스의 특징은 다음과 같습니다.
첫 번째, Inner클래스의 인스턴스는 Outer 클래스의 인스턴스 없이는 생성이 불가능 합니다. Inner 클래스의 인스턴스는 반드시 Outer 클래스의 인스턴스에 종속되어야 하기 때문입니다.
두 번째, Inner클래스 내에서는 Outer 클래스의 멤버에 직접접근이 가능합니다. Inner 클래스는 Outer클래스의 내부에 정의되기 때문에 Outer클래스의 멤버가 private로 선언되더라도 접근이 가능합니다.
세 번째, Inner클래스의 인스턴스는 자신이 속할 Outer클래스의 인스턴스를 기반으로 생성됩니다.
네 번째, Inner클래스는 클래스들을 논리적으로 묶는 수단으로 사용이 가능합니다. 그렇기 때문에 캡슐화가 증가하는 효과를 기대할 수 있습니다. 캡슐화가 증가함으로써 코드의 가독성 증대는 물론 유지보수가 용이해지게 됩니다.
Local 클래스란?
Local 클래스는 Inner 클래스와 유사한 구조를 띄고 있습니다. 다만 그 차이점은 Local 클래스는 메소드 내에 정의되는 클래스라는 점입니다. 그렇기 때문에 정의된 메소드 내에서만 인스턴스의 생성 및 참조변수의 선언이 가능합니다. 아래의 코드르 통해 설명하겠습니다.
class Out { public LocalClass declareLocal() { // Local 클래스의 이름이 반환형이다. 이것은 문제가된다. class LocalClass { . . . } return new LocalClass(); } }
위의 코드를 확인해보면 declareLocal 메소드 내에 Local 클래스가 정의된 것을 확인할 수 있습니다. 앞서 설명했듯이 정의된 메소드 내에서 인스턴스의 생성 및 참조변수릐 선언이 가능하기 때문에 return new LocalClass() 에서 처럼 인스턴의 생성이 가능합니다.
하지만 declareClass 메소드의 반환형을 보면 반환형이 LocalClass인 것을 확인할 수 있습니다. Local 클래스는 메소드 내에서만 의미가 있기때문에 Local클래스의 이름이 반환형일 수 없습니다.
이런 상황을 해결하기 위해 우리는 interface를 활용해야합니다. 활용의 예시는 아래와 같습니다.
interface MakeAvailable { public void make(); } class Out { public MakeAvailable declareLocal() { class LocalClass implements MakeAvailable { public void make() { . . . } } return new LocalClass(); } }
위의 코드를 확인해본 결과, Local 클래스가 정의되면 Local 클래스의 인스턴스에 접근하기 위해서 interface를 정의합니다. 이처럼 Local 클래스가 정의되면 interface를 함께 정의함으로써 Local클래스의 인스턴스 접근이 가능하다는 것을 알 수 있습니다.
Local 클래스와 매개변수
Local 클래스는 메소드 내부에 정의되기 때문에 매개변수와 지역변수의 접근이 가능합니다. 하지만 여기에는 조건이 있습니다. final로 선언된 매개변수와 지역변수에만 접근이 가능하다는 것입니다. 그렇다면 그 이유는 무엇일까?
이유를 설명하기에 앞서 매개변수와 지역변수의 특징을 생각해봅시다. 매개변수와 지역변수는 메소드를 벗어나게되면 소멸되게 됩니다. 아래의 코드를 예시로 상세한 설명을 하도록 하겠습니다.
interface MakeAvailable { public void make(); } class Out { private String name; Out(String name){ this.name=name; } public MakeAvailable declareLocal(final int num) { class LocalClass implements MakeAvailable { public void make() { System.out.println("Outer Class Instance Name : " + name); System.out.println("Local Class Instance Num : " + num); } } return new LocalClass(); } } class Test { public static void main (String[] args) { Out out = Out("Outer Class"); MakeAvailable localInstanceOne = out.declareLocal(123); localInstanceOne.make(); MakeAvailable localInstanceTwo = out.declareLocal(456); localInstanceTwo.make(); } }
Test 클래스 내부에서 MakeAvailable localInstanceOne = out.declareLocal(123); 를 통해 declareLocal 메소드가 호출됨을 확인할 수 있습니다. 이를 통해 인스턴스가 생성되고 localInstanceOne은 앞서 생성된 인스턴스를 참조하는 참조변수 입니다. 이 과정이 끝나면서 declareLocal 메소드는 종료되고 123으로 초기화되었던 매개변수인 num은 소멸됩니다. 하지만 바로 다음줄에서 make() 메소드를 통해 123으로 초기화됬었던 num 값의 출력은 가능합니다.
이처럼 매개변수나 지역변수가 소멸되는 문제를 해결하기 위해 Local 클래스에 접근하는 매개변수 및 지역변수의 복사본을 Local클래스가 언제나 접근가능한 메모리 영역에 복사해두게됩니다. 이러한 이유로인해 매개변수 및 지역변수를 final로 선언하는 것입니다. Local 클래스 내에서 값의 변경을 제한함으로써 원본과 복사본의 값의 일치하게 만들어주는 것입니다.
Anonymous 클래스란?
위에서 Local 클래스와 Inner 클래스를 설명했습니다. 지금 설명할 Anonymous 클래스 또한 이들과 유사한 성격을 띄고 있습니다. 이 Anonymous 클래스의 Local 클래스와의 차이점은 클래스의 이름 유무입니다. Anonymous 클래스는 클래스의 이름이 없는 클래스입니다. 이러한 Anonymous 클래스는 interface에 메소드를 채워 넣는 방식으로 정의합니다.
Local 클래스를 설명할 때 사용했던 코드를 Anonymous 클래스로 변형한 코드는 다음과 같습니다.
interface MakeAvailable { public void make(); } class Out { private String name; Out(String name){ this.name=name; } public MakeAvailable declareLocal(final int num) { return new MakeAvailable() { public void make() { System.out.println("Outer Class Instance Name : " + name); System.out.println("Local Class Instance Num : " + num); } }; } } class Test { public static void main (String[] args) { Out out = Out("Outer Class"); MakeAvailable localInstanceOne = out.declareLocal(123); localInstanceOne.make(); MakeAvailable localInstanceTwo = out.declareLocal(456); localInstanceTwo.make(); } }
위의 코드는 Local 클래스에서 설명했던 코드와 동일한 결과를 출력합니다. MakeAvailable은 interface이므로 인스턴스의 생성이 불가능하다는 것은 알고 있으실 것입니다. 인스턴스가 생성 불가능한 이유는 메소드가 완전하게 정의되어 있지 않기때문인데, 위의 코드처럼 메소드를 채워 넣음으로서 인스턴스의 생성이 가능하게 되는 것입니다.
한가지 주의할 점으로는 이러한 Anonymous 클래스는 interface의 메소드를 채워 넣어 완성하는 방식으로 정의되기 때문에 생성자가 필요로 되는 상황에서는 사용하지 않습니다. 클래스의 이름이 없기때문에 생성자를 정의할 수 없기 때문이죠.
'Java > 개념 정리' 카테고리의 다른 글
[Camel][Java] JVM(가상머신)의 메모리 모델 (0) 2020.02.27 [Camel][Java] 예외처리 (feat. try~catch문) (0) 2020.02.24 [Camel][Java] Abstract Class (추상클래스)와 Interface(인터페이스) (0) 2020.02.21 [Camel][Java] Object 클래스에 대해서 (0) 2020.02.21 [Camel][Java] 상속을 위한 관계 (IS-A, HAS-A) 그리고 오버라이딩 (0) 2020.02.20