Effective Java - Item 24. 멤버 클래스는 되도록 static으로 만들어라
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