728x90
1. 중첩클래스란
중첩 클래스(nested class) : 다른 클래스 안에 정의된 클래스
- 정적 멤버 클래스
- (비정적) 멤버 클래스
- 익명 클래스
- 지역클래스
정적 멤버 클래스를 제외한 나머지는 내부 클래스라고 한다 (inner class)
2. 정적 멤버 클래스
일반 클래스와 다른점
- 다른 클래스 안에 선언된다.
- 바깥 클래스의 private 멤버에도 접근할 수 있다.
다른 정적 멤버와 똑같은 접근 규칙을 적용받는다.
바깥 클래스와 함께 쓰이는 public 도우미 클래스로 사용된다.
public class Calculator{
public enum Operator{ // 열거타입도 정적 멤버 클래스이다
PLUS(),MINUS()
}
public static class Operator{ // 대부분 이처럼 선언
}
}
3. 비정적 멤버 클래스
정적 멤버 클래스와의 차이
- 구문상 차이 : static이 있고 없고 차이
- 의미상 차이 : 비정적 멤버 클래스의 인스턴스와 바깥 클래스의 인스턴스와 연결된다.
- 정규화된 this를 이용해 바깥 인스턴스의 인스턴스 메서드 호출이 가능하다.
클래스명.this
개념상 중첩 클래스의 인스턴스가 바깥 클래스의 인스턴스와 독립적으로 존재할 수 있다면 정적 멤버 클래스로 만들어야한다.
비정적 멤버클래스는 바깥 인스턴스 없이는 생성할 수 없다.
public class NestedNonStaticExample {
private final String name;
public NestedNonStaticExample(String name) {
this.name = name;
}
public String getName() {
// 비정적 멤버 클래스와 바깥 클래스의 관계가 확립되는 부분
NonStaticClass nonStaticClass = new NonStaticClass("nonStatic : ");
return nonStaticClass.getNameWithOuter();
}
private class NonStaticClass {
private final String nonStaticName;
public NonStaticClass(String nonStaticName) {
this.nonStaticName = nonStaticName;
}
public String getNameWithOuter() {
// 정규화된 this 를 이용해서 바깥 클래스의 인스턴스 메서드를 사용할 수 있다.
return nonStaticName + NestedNonStaticExample.this.getName();
}
}
}
비정적 멤버 클래스의 인스턴스와 바깥 인스턴스 사이의 관계는 멤버 클래스가 인스턴스화될 때 확립되며, 더이상 변경할 수 없다.
드물게 직접 [바깥 인스턴스의 클래스].new MebmerClass(agrs)
를 호출해 수동으로 만든다. 그러나 이 관계정보는 비정적 멤버 클래스의 인스턴스 안에 만들어져 메모리 공간을 차지하며, 생성시간도 더 걸린다.
NestedNonStaticExample nestedNonStaticExample = new NestedNonStaticExample("name");
nestedNonStaticExample.new NonStaticPublicClass();
비정적 멤버 클래스의 쓰임 : 어댑터의 역할
- 어떤 클래스의 인스턴스를 감싸 마치 다른 클래스의 인스턴스처럼 보이게 하는 뷰로 사용한다.
- Map 인터페이스의 구현체 : 컬렉션 뷰를 구현할 때 비정적 멤버 클래스를 사용
- 컬렉션 인터페이스 구현체 : 자신의 반복자 구현
멤버 클래스에서 바깥 인스턴스에 접근할 일이 없다면 무조껀 static을 붙여서 정적 멤버클래스로 만들자
- 숨은 외부 참조를 갖게되며, 이 참조를 저장하기 위한 시간과 공간이 소비된다.
- GC가 바깥 클래스의 인스턴스를 수거하지 못하는 메모리 누수가 생길 수 있다.
4. 익명 클래스
- 이름이 없다!
- 바깥 클래스의 멤버도 아니다.
- 쓰이는 시점에 선언과 동시에 인스턴스가 만들어진다.
- 비정적인 문맥에서 사용될 때만 바깥 클래스의 인스턴스 참조가 가능하다
- 상수 정적변수 (
static final
) 외에는 정적 변수를 가질 수 없다.
public class AnonymousExample {
private double x;
private double y;
public double operate() {
Operator operator = new Operator() {
@Override
public double plus() {
System.out.printf("%f + %f = %f\n", x, y, x + y);
return x + y;
}
@Override
public double minus() {
System.out.printf("%f - %f = %f\n", x, y, x - y);
return x - y;
}
};
return operator.plus();
}
}
interface Operator {
double plus();
double minus();
}
익명 클래스의 제약사항
- 선언한 지점에서만 인스턴스를 만들수 있다.
- Instanced 검사, 클래스 이름이 필요한 검사를 할 수 없다.
- 여러 인터페이스를 구현할 수 없다. 구현과 동시에 다른클래스 상속도 불가능하다.
- 익명 클래스 사용 클라이언트는 사용하는 익명 클래스가 상위타입에서 상속한 멤버외에는 호출이 불가능하다
- 표현식 중간에 등장해 10줄이 넘어가면 가독성이 좋지 않다.
사용 예시
- 람다(자바7) 등장 이전에는 작은 함수 객체나 처리 객체 구현에 사용되었다 : 람다를 쓰자
- 정적 팩터리 메서드를 구현할 때 사용되기 도한다.
5. 지역클래스
- 가장 드물게 사용된다.
- 지역변수를 선언할 수 있는 곳이면 어디서든 선언할 수 있다
- 지역변수와 유효범위가 같다
- 멤버 클래스 유사도 : 이름이 있고 반복해서 사용이 가능하다
- 익명 클래스 유사도 : 비정적 문맥에서 사용할 때만 바깥 인스턴스 참조가 가능하다
- 익명 클래스 유사도 : 정적 멤버는 가질 수 없고, 가독성을 위해 짧게 작성한다.
public class LocalExample {
private int number;
public LocalExample(int number) {
this.number = number;
}
public void foo() {
// 지역변수처럼 선언해서 사용할 수 있다.
class LocalClass {
private String name;
public LocalClass(String name) {
this.name = name;
}
public void print() {
// 비정적 문맥에선 바깥 인스턴스를 참조 할 수 있다.
System.out.println(number + name);
}
}
LocalClass localClass = new LocalClass("local");
localClass.print();
}
}
'Dev Book Review > Effective Java' 카테고리의 다른 글
[Effective Java] Chapter 4: 클래스와 인터페이스 (0) | 2020.05.05 |
---|---|
[Effective Java] item25. 톱레벨 클래스는 한 파일에 하나만 담으라 (0) | 2020.05.05 |
[Effective Java] item23. 태그 달린 클래스보다는 클래스 계층 구조를 활용하라하라 (0) | 2020.05.05 |
[Effective Java] item22. 인터페이스는 타입을 정의하는 용도로만 사용하라 (0) | 2020.05.05 |
[Effective Java] item21. 인터페이스는 구현하는 쪽을 생각해 설계하라 (0) | 2020.05.05 |