Book/Effective Java

Effective Java - Item 24. 멤버 클래스는 되도록 static으로 만들어라

성공종 2023. 3. 22. 22:06

24. 멤버 클래스는 되도록 static으로 만들어라

중첩 클래스(nested class)는 다른 클래스 내부에 정의된 클래스를 말한다.
nested class는 해당 클래스가 선언 된 클래스 내부에서만 사용해야하며 그렇지 않다면 그냥 밖에다 만들어야한다.

nested class의 종류에는 static member classes, nonstatic member classes, anonymous classes, local classes가 있다.
static과 nonstatic은 익히 봐 왔으니 넘어가고 anonymous classes와 local classes에 대해 살펴보겠다.
anonymous classes는 아래의 코드를 보면 이해가 쉽게 간다.

public class Example {

    interface MyInterface {
        void doSomething();
    }

    public static void main(String[] args) {

        MyInterface myClass = new MyInterface() {
            @Override
            public void doSomething() {
                System.out.println("doSomething");
            }
        };
        myClass.doSomething();
    }
}

public class Example2 {

    public static abstract class MyAbstractClass {
        public abstract void doSomething();
    }

    public static void main(String[] args) {

        MyAbstractClass myClass = new MyAbstractClass() {
            @Override
            public void doSomething() {
                System.out.println("doSomething");
            }
        };
        myClass.doSomething();
    }
}

interface 혹은 abstact class 심지어 그냥 일반 class를 그 때 그 때 implements 혹은 extends 하여 사용하는 class이다.
해당 클래스의 구현체는 이름이 존재하지 않고 그 순간 순간 사용되고 사라진다.
상위 클래스가 interface가 아니었다면 부모 객체의 field를 참조할 수 있게된다.
anonymous classes는 그 때 그 때 나만의 클래스를 만들어 쓰자가 목적이다. 그냥 지금은 lambda를 쓰자

local class는 아래와 같다.

class OuterClass {
    public void doSomething() {
        class LocalClass { // 로컬 클래스
            public void doSomething() {
                // ...
            }
        }

        LocalClass obj = new LocalClass();
        obj.doSomething();
    }
}

오우. 함수 내부에서 클래스가 정의되고 이 해당 함수의 scope 밖에서는 접근할 수 없다.
local 클래스 또한 밖에 선언 된 outer class의 field에 접근 할 수 있다.

이 중 static member classes를 제외하면 전부 inner class이다. inner class의 정의가 감이 올것 같다.
inner class는 나 자신을 감싸는 outer class의 field에 접근 할 수 있느냐 없느냐로 분기가 갈린다.
어찌보면 당연하다. 선언이 static으로 된 class는 outer class의 instance 생성 없이도 호출이 가능하기 때문에 outer class의 필드가 애초에 없다.
앞으로 남은 이야기도 outer class의 instance가 생성 된 이후에 생성되어야 하는 inner class이냐 아니냐의 성질로 이야기가 이어진다.

class OuterClass {
    class LocalClass {
    }
}
new OuterClass().new LocalClass();

보통은 OuterClass가 생성 될 때 그 내부에서 LocalClass를 생성하지만 위의 코드처럼 나중에 생성할 수도 있다.
LocalClass의 내부 instance 안에 OuterClass와의 연관 관계를 저장해야해서 메모리를 더 많이 먹고 생성도 오래 걸리게 된다.

nonstatic member classes는 Adapter를 정의할 때 자주 쓰인다

public class MySet<E> extends AbstractSet<E> {

    @Override
    public Iterator<E> iterator() {
        return new MyIterator();
    }

    private class MyIterator implements Iterator<E>{

    }
}

요런 식으로 나만의 커스텀 Iterator를 만들고 싶을 때 쓸 수 있다.
inner class의 특징 -> 바깥 클래스의 instance를 참조할 일이 없으면? == nested 클래스를 static으로 만들자
위에서도 말했듯이 inner class는 outer class의 숨은 참조를 가져서 메모리를 낭비하고 바깥 클래스의 메모리를 수거하지 못할 수도있다.
static member classes를 잘 활용한 사례는 Map.Entry 객체이다.

// 하이 하이 ㅋㅋ
 interface Entry<K, V> {
        /**
         * Returns the key corresponding to this entry.
         *
         * @return the key corresponding to this entry
         * @throws IllegalStateException implementations may, but are not
         *         required to, throw this exception if the entry has been
         *         removed from the backing map.
         */
        K getKey();
        ...

Map은 모든 Entry를 참조하지만 Entry는 Map을 참조할 필요가 없다.
이런식으로 어떤 클래스 내부의 구성요소로써만 사용이 되는 경우 자주 쓰인다.

 

 

GitHub - ssafystudy/EffectiveJava

Contribute to ssafystudy/EffectiveJava development by creating an account on GitHub.

github.com