728x90
1. 중첩 클래스(Nested Class)
- 다른 클래스 안에 정의된 클래스 (자신을 감싼 바깥 클래스 에서만 사용되어야 하며, 그 외의 쓰임새가 잇다면 톱레벨 클래스로 따로 클래스 파일에 정의해야함
종류
- 정적 멤버 클래스
- (비정적) 멤버 클래스
- 익명 클래스
- 지역 클래스
2. 각각의 특징
-
정적 멤버 클래스 vs 비정적 클래스 (클래스 앞에 static 키워드가 붙냐 안붙냐 차이)
- 비정적 클래스는 바깥 클래스의 인스턴스와 암묵적으로 참조함(바깥 인스턴스의 메소드 및 참조 접근 가능)
- 바깥 인스턴스와 독립적인 존재로 만들고 싶다면 반드시 정적 멤버 클래스로 선언해야함(비 정적 클래스는 참조를 지우더라도 바깥 클래스가 계속해서 참조하므로 가비지 컬렉션이 메모리를 수거하지 못함)
- 비정적 멤버 클래스는 어댑터 패턴에서 자주 사용됨(다른 클래스를 깜싸 다른 인스턴스 처럼 보이게 하는 뷰)
- 정적 멤버 클래스는 바깥 클래스가 표현하는 구성요소를 나타날떄 사용
- 접근범위가 public 이나 protected가 될 경우 정적이냐 아니냐가 더 중요해짐
/* Hash Map에 존재하는 비정적 , 정적 멤버 클래스 */
final class KeySet extends AbstractSet<K> {
public final int size() { return size; }
public final void clear() { HashMap.this.clear(); }
public final Iterator<K> iterator() { return new KeyIterator(); }
public final boolean contains(Object o) { return containsKey(o); }
public final boolean remove(Object key) {
return removeNode(hash(key), key, null, false, true) != null;
}
public final Spliterator<K> spliterator() {
return new KeySpliterator<>(HashMap.this, 0, -1, 0, 0);
}
public final void forEach(Consumer<? super K> action) {
Node<K,V>[] tab;
if (action == null)
throw new NullPointerException();
if (size > 0 && (tab = table) != null) {
int mc = modCount;
for (Node<K,V> e : tab) {
for (; e != null; e = e.next)
action.accept(e.key);
}
if (modCount != mc)
throw new ConcurrentModificationException();
}
}
}
/*맵은 노드를 구성요소로 사용하지만, 노드는 맵을 직접 사용할 일이 절대 없음 => 정적 멤버 클래스로 선언*/
static class Node<K,V> implements Map.Entry<K,V> {
final int hash;
final K key;
V value;
Node<K,V> next;
Node(int hash, K key, V value, Node<K,V> next) {
this.hash = hash;
this.key = key;
this.value = value;
this.next = next;
}
public final K getKey() { return key; }
public final V getValue() { return value; }
public final String toString() { return key + "=" + value; }
public final int hashCode() {
return Objects.hashCode(key) ^ Objects.hashCode(value);
}
public final V setValue(V newValue) {
V oldValue = value;
value = newValue;
return oldValue;
}
public final boolean equals(Object o) {
if (o == this)
return true;
if (o instanceof Map.Entry) {
Map.Entry<?,?> e = (Map.Entry<?,?>)o;
if (Objects.equals(key, e.getKey()) &&
Objects.equals(value, e.getValue()))
return true;
}
return false;
}
}
-
익명 클래스 : 이름 없는 클래스
- 바깥 클래스의 멤버가 아님(선언과 동시에 인스턴스화)
- 클래스 이름이 필요한 검사 제한적 (instance of, getclass 등)
- 자바 8버전 이후부터는 람다를 주로 사용함 !
PriorityQueue <Integer> pq = new PriorityQueue<Integer>(new Comparator<>() {
@Override
public int compare(Integer o1, Integer o2) {
return o1-o2;
}
});
-
지역 클래스
-지역변수를 선언할수 있는 곳에서 사용 가능 (유효범위도 같음)
- 이름이 있고 반복적으로 사용가능하나 유효범위내에서만 사용가능 정적멤버 X (넷중에서 가장 드물게 사용됨)
'JAVA > Effective Java' 카테고리의 다른 글
item28) 배열보다는 리스트를 사용하라 (0) | 2021.01.31 |
---|---|
item 27) 비검사 경고를 제거하라 (0) | 2021.01.22 |
item 25) 톱레벨 클래스는 한 파일에 하나만 담으라 (0) | 2021.01.15 |
item 18) 상속보다는 컴포지션을 사용하라 (0) | 2021.01.11 |
item 13) clone 재정의는 주의해서 진행하라 (0) | 2021.01.04 |