Item24 - 멤버 클래스는 되도록 static으로 만들라

2023. 12. 3. 19:53Book/이펙티브 자바

 

중첩 클래스란 다른 클래스 안에 정의된 클래스를 말한다. 중첩 클래스는 자신을 감싼 바깥 클래스에서만 쓰여야 하며, 그 외의 쓰임새가 있다면 톱 레벨 클래스로 만들어야 한다.

 

네 종류의 중첩 클래스와 각각의 쓰임

 

1. 정적 멤버 클래스

public class OutterClass {
    private static int number = 10;

    private static class InnerClass {
        void doSomething() {
            System.out.println(number);
        }
    }

    public static void main(String[] args) {
        InnerClass innerClass = new InnerClass();
        innerClass.doSomething();
    }
}

 정적 멤버 클래스는 바깥 클래스와 함께 쓰일 때만 유용한  public 도우미 클래스로 쓰인다.

 

2. 비정적 멤버 클래스

 - 바깥 클래스의 인스턴스와 암묵적으로 연결된다.

 - 어댑터를 정의할 때 자주 쓰인다.

 - 멤버 클래스에서 바깥 인스턴스를 참조할 필요가 없다면 무조건 정적 멤버 클래스로 만들자

public class OutterClass {

    private int number = 10;
    void printNumber() {
        InnerClass innerClass = new InnerClass();
    }

    private class InnerClass {
        void doSomething() {
            System.out.println(number);
            OutterClass.this.printNumber();
        }
    }

    public static void main(String[] args) {
        InnerClass innerClass = new OutterClass().new InnerClass();
        innerClass.doSomething();
    }
}

=> static을 생략하면 바깥 인스턴스로의 숨은 외부 참조를 갖게 된다. 이 참조를 저장하려면 시간과 공간이 소비된다. 더 심각한 문제는 가비지 컬렉션이 바깥 클래스의 인스턴스를 수거하지 못해 메모리 누수가 발생 할 수 있는 점이다(item7)

 

 

3. 익명 클래스

 - 바깥 클래스의 멤버가 아니며, 쓰이는 시점과 동시에 인스턴스가 만들어진다.

 - 비정적인 문맥에서 사용될 때만 바깥 클래스의 인스턴스를 참조할 수 있다.

 - 자바에서 람다를 지원하기 전에 즉석에서 작은 함수 객체나 처리 객체를 만들 때 사용했다.

 - 정적 팩터리 메서드를 만들 때 사용할 수도 있다.

// 코드 20-1 골격 구현을 사용해 완성한 구체 클래스 (133쪽)
public class IntArrays {
    static List<Integer> intArrayAsList(int[] a) {
        Objects.requireNonNull(a);

        // 다이아몬드 연산자를 이렇게 사용하는 건 자바 9부터 가능하다.
        // 더 낮은 버전을 사용한다면 <Integer>로 수정하자.
        //!!!!!!!!익명 클래스!!!!!!!!!!!
        return new AbstractList<>() {
            @Override public Integer get(int i) {
                return a[i];  // 오토박싱(아이템 6)
            }

            @Override public Integer set(int i, Integer val) {
                int oldVal = a[i];
                a[i] = val;     // 오토언박싱
                return oldVal;  // 오토박싱
            }

            @Override public int size() {
                return a.length;
            }
        };
    }
}

 

4. 지역 클래스

 - 가장 드물게 사용된다.

 - 지역 변수를 선언하는 곳이면 언제든 지역 클래스를 정의해 사용할 수 있다.

 - 가독성을 위해 짧게 작성해야 한다.