티스토리 뷰
study/Effective Java
[Effective Java] item 24. 멤버 클래스는 되도록 static으로 만들어라
wookcode 2022. 9. 11. 23:43728x90
반응형
item 24. 멤버 클래스는 되도록 static으로 만들어라
중첩클래스
다른 클래스 안에 정의된 클래스를 말한다.
- 자신을 감싼 바깥 클래스에서만 사용되어야 한다.
- 중첩 클래스를 사용함으로써 불필요한 노출을 줄여 캡슐화를 할 수 있고 유지보수하기 좋은 코드를 작성할 수 있다.
중첩 클래스 종류
- 정적 멤버 클래스
- 비정적 멤버 클래스
- 익명 클래스
- 지역 클래스
정적 멤버 클래스
정적 멤버 클래스와 비정적 멤버 클래스를 구분하는 기준은 static 키워드가 함께 작성되었는지 여부로 판단할 수 있다.
class Outer {
private int out = 100;
static class Inner {
private int in;
void callOut() {
Outer outer = new Outer();
System.out.println(outer.out);
}
}
}
- 정적 멤버 클래스는 외부 클래스의 private 멤버에도 접근할 수 있다는 점만 제외하고는 일반 클래스와 똑같다.
// 정적 멤버클래스 인스턴스 생성
Outer.Inner inner = new Inner();
비정적 멤버 클래스
static 키워드 없는 내부 클래스이다.
class Outer {
private int out = 100;
class Inner {
private int in;
}
}
- 비정적 멤버 클래스의 인스턴스는 바깥 클래스의 인스턴스와 암묵적으로 연결된다.
- 그러므로 비정적 멤버 클래스는 this 키워드로 바깥 인스턴스의 메서드를 호출하거나 참조를 가져올 수 있다.
class Outer {
private int out = 100;
public void create(){
...
}
class Inner {
private int in;
void accessOuter(){
Outer.this.create(); // 정규화된 this (클래스명.this)
}
}
}
// 비정적 멤버클래스 인스턴스 생성
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();
비정적 멤버 클래스 활용
비정적 멤버 클래스는 어댑터를 정의할 때 자주 사용된다.
즉, 어떤 클래스의 인스턴스를 감싸 마치 다른 클래스의 인스턴스처럼 보이게 하는 뷰로 사용하는 것이다.
예컨대 Map 인터페이스의 구현체들은 보통(KeySet, entrySet, values 메서드가 반환하는) 자신의 컬렉션 뷰를 구현할 때 비정적 멤버 클래스를 사용한다.
예를 들어 HashMap의 keySet()을 사용하면 Map의 key의 해당하는 값들을 Set으로 반환할 때 어댑터 패턴을 이용해서 Map을 Set으로 제공한다.
참고 : https://insight-bgh.tistory.com/409
비슷하게, Set과 List 같은 다른 컬렉션 인터페이스 구현들도 자신의 반복자를 구현할 때 비정적 멤버 클래스를 주로 사용한다.
public class MySet<E> extends AbstractSet {
@Override
public Iterator iterator() {
return new MyIterator();
}
private class MyIterator implements Iterator<E>{
...
}
}
멤버 클래스에서 바깥 인스턴스에 접근할 일이 없다면 무조건 static을 붙여서 정적 멤버 클래스로 만들자.
비정적 멤버 클래스를 사용하면 바깥 인스턴스로의 숨은 외부 참조를 갖게된다. 이 참조를 저장하려면 시간과 공간이 소비된다.
더 심각한 문제는 가비지 컬렉션이 바깥 클래스의 인스턴스를 수거하지 못하도록 하는 메모리 누수가 생길 수도 있다.
따라서 멤버 클래스에서 바깥 인스턴스에 접근할 일이 없다면 static을 붙이는게 좋다.
익명 클래스
- 이름이 없다.
- 바깥 클래스의 멤버가 아니다.
- 코드의 어디서든 만들 수 있다.
public class TestClass {
Integer intInstance = 10;
void doX() {
SInterface sInterface = new SInterface() {
@Override
public void doSomething() {
//바깥 인스턴스 참조
System.out.println(intInstance);
}
};
sInterface.doSomethint();
}
}
interface SInterface {
void doSomething();
}
지역 클래스
static 멤버는 갖지 못하며, 클래스 내부에서 필요한 기능을 정의할 때 사용한다.
- 네가지 중첩 클래스중 가장 드물게 사용된다.
- 지역 변수를 선언할 수 있는 곳이면 어디서든 선언이 가능하다.
- 유효 범위도 지역변수와 같다.
public class TestClass {
void x() {
class LocalClass {
void doPrint() {
System.out.println("LocalClass");
}
}
}
}
Reference
반응형
'study > Effective Java' 카테고리의 다른 글
[Effective Java] item 41. 정의하려는 것이 타입이라면 마커 인터페이스를 사용하라 (0) | 2022.11.13 |
---|---|
[Effective Java] item 31. 한정적 와일드카드를 사용해 API 유연성을 높이라 (0) | 2022.10.25 |
[Effective Java] item 16. public 클래스에서는 public 필드가 아닌 접근자 메서드를 사용하라 (0) | 2022.08.20 |
[Effective Java] item 12. toString을 항상 재정의하라 (0) | 2022.08.06 |
[Effective Java] item 11. equals를 재정의하려거든 hashCode도 재정의하라 (0) | 2022.08.06 |
댓글