자바에서 중첩(nested)클래스는 4가지로 나뉩니다.
1. 정적 멤버 클래스(static member class)
2. 비 정적 멤버 클래스(non-static member class)
3. 익명 클래스
4. 지역 클래스
먼저 정적 멤버 클래스는 가장 간단한 중첩클래스 형태입니다. 클래스 안쪽에 static 클래스를 선언해
바깥 클래스를 사용할 때 클래스를 자동으로 생성시켜주는 역할을 합니다.
바깥 클래스를 사용할 때 자연스럽게 사용되는 헬퍼 클래스의 역할을 하는 만큼,
매번 바깥 클래스를 호출할 때마다
내부 클래스를 재생성하는건 메모리 효율상 좋지 않기 때문에
내부 클래스에서 바깥 객체에 접근할 필요가 없는 클래스의 경우 static을 붙여 생성시켜놓고 쓰게끔 하는 것입니다.
이 경우 정적 멤버 클래스는 바깥 클래스의 모든 변수에 접근이 가능합니다. private 으로 만들어져있다 하더라도요.
public class Main {
private int x = 10;
private static class InnerClass {
void test() {
Main outerClass = new Main();
outerClass.x = 100;
}
}
}
이는 내부에 클래스 객체를 만들고 private에 접근하는 모습을 보여줍니다.
비 정적 멤버 클래스는 바깥 객체와 자동적으로 연결됩니다.
비 정적 멤버 클래스 안에서는 바깥 클래스의 메소드를 호출할 수도 있고, this 한정 구문을 통해 바깥 객체에 대한 참조도 획득할 수 있습니다.
public class Main {
void Hello(){
System.out.println("Hello");
}
private class InnerClass {
void test() {
Main.this.Hello();
}
}
}
이런 식으로 말이죠. 비 정적 멤버 클래스는 정적 멤버 클래스와 다르게
바깥 클래스의 존재 없이는 존재할 수 없는 클래스입니다. 때문에 이 클래스만 독립적으로 존재하도록 하고 싶다면
중첩 클래스는 반드시 static을 붙여줘야합니다.
예로 Map과 Entry의 관계가 있습니다.
Map에는 키값을 관리하기 위한 Entry 객체를 사용하는데 이 Entry 객체는 Map의 객체에 접근할 필요가 없습니다.
이럴 때 Entry 클래스를 비 정적 멤버 클래스로 만들어준다면, Entry 클래스는 매번 Map에 대한 주소참조를 유지하고 있을 것입니다.
이러한 낭비를 줄이기 위해 static을 붙여 메모리에 직접 관리하는 것이 공간, 시간이 의득이라는 것이지요.
익명 클래스는 한번만 사용할 수 있고, 상속할 수 없는 클래스를 말합니다.
또한 복수의 인터페이스를 구현하는 것도 불가능합니다.
이 클래스는 표현식만 준수한다면 어디서든 사용할 수 있습니다.
public class Main {
Inner innerClass(){
return new Inner() {
@Override
public void hello(String a) {
System.out.println("Hello!");
}
};
}
interface Inner {
void hello(String a);
}
}
익명클래스의 예는 이렇게 될 수 있습니다
인터페이스를 필요한 순간 구현해버리고 객체를 넘기죠. 편리하지면 재사용이 불가능하고
멀티 구현이 안된다는 점이 단점입니다.
이 코드는 자바 1.5부터 람다식으로 대체 가능합니다.
public class Main {
Inner innerClass(){
return (String a) -> {
System.out.println("Hello!" + a);
};
}
interface Inner {
void hello(String a);
}
}
마지막으로 지역 클래스는 메소드 안에 형성되며, 용도는 익명 클래스와 유사합니다.
메소드 내부에서 필요한 기능을 정의할 때 사용합니다.static 멤버는 가질 수 없습니다.
간단하게 코드를 짜봤습니다.
public class Main {
private int main = 1;
void local(){
// .. inside method
class localClass{
private int x=2;
void sum(){ System.out.println( main + x ); }
}
localClass localClass = new localClass();
localClass.sum();
} // end local method
public static void main(String[] args){ // main of Main Class
Main main = new Main();
main.local();
}
}
main 안에 local 메소드가 있고 local 메소드 안에 로컬 클래스가 있습니다.
용도를 보시며 알겠지만 익명클래스처럼 이용한 편의성을 우선한 코드입니다.
하지만 자주 쓰이는 익명클래스에 비해 사용빈도는 매우 낮습니다.
사실상 굳이 구현하지 않아도, 해결할 수 있는 방법이 많고
또 저런 코드는 길어지면 정말 읽기 힘든 코드가 됩니다...
각 고유의 특성을 확인하고 적합한 클래스를 사용하도록 합시다.
'프로그래밍 > Java' 카테고리의 다른 글
이펙티브 자바 규칙 23 - 새 코드에는 무이자 제네릭 자료형을 사용하지 마라 (0) | 2018.03.08 |
---|---|
이펙티브 자바 규칙 21 - 전략을 표현하고 싶을 때는 함수 객체를 사용해라 (0) | 2018.02.21 |
이펙티브 자바 규칙 20 - 태그가 달린 클래스 대신 클래스 계층을 활용하라 (0) | 2018.02.20 |