Effective Java - item 25
톱 레벨 클래스는 한 파일에 하나만 담으라
들어가며
소스 파일 하나에 톱레벨 클래스를 여러 개 선언하더라도 자바 컴파일러는 불평하지 않는다. 하지만 아무런 득이 없을 뿐더러 심각한 위험이 발생할 수도 있다. 컴파일 순서에 따라 결과가 달라질 수도 있기 때문이다.
예시
1
2
3
4
5
6
// (Page 115)
public class Main {
public static void main(String[] args) {
System.out.println(Utensil.NAME + Dessert.NAME);
}
}
먼저 Main 클래스 하나를 담고있고 Main 클래스는 다른 톱 레벨 클래스 2개 (Utensil, Dessert)를 참조한다.
1
2
3
4
5
6
7
8
//Two classes defined in one file. Don't ever do this! (Page 115)
class Utensil {
static final String NAME = "pot";
}
class Dessert {
static final String NAME = "pie";
}
또한 위와 같이 Utensil, Dessert의 클래스가 Utensil.java라는 한 파일에 정의되어있을때는 문제가 없다.
1
2
3
4
5
6
7
8
9
// Two classes defined in one file. Don't ever do this! (Page 115)
class Utensil {
static final String NAME = "pan";
}
class Dessert {
static final String NAME = "cake";
}
하지만 이렇게 똑같은 클래스를 담은 Dessert.java로 만들었다면 문제가 발생할 수도 있다.
문제 발생 이유
javac Main.java Dessert.java의 명령으로 컴파일한다면 오류가 나고 Dessert의 중복 정의를 했다고 알려줄 것이다.javac Main.java나javac Main.java Utensil.java명령으로 컴파일한다면 pancake을 출력한다.javac Dessert.java Main.java명령으로 컴파일 한다면 potpie를 출력한다.
이처럼 컴파일러에 어느 소스 파일을 먼저 건네느냐에 따라 동작이 달라지므로 해결해야 한다.
정적 멤버 클래스
해결책은 서로 다른 클래스로 분리하면 그만이지만 굳이 한 파일에 담고싶다면 정적 멤버 클래스를 사용하는 방법을 고민해보면 된다. 다른 클래스에 딸린 부차적인 클래스라면 정적 멤버 클래스로 만드는 쪽이 일반적으로 더 좋다. 읽기 편하고, private으로 선언하면 접근 범위도 최소화 할 수 있기 때문이다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Static member classes instead of multiple top-level classes (Page 116)
public class Test {
public static void main(String[] args) {
System.out.println(Utensil.NAME + Dessert.NAME);
}
private static class Utensil {
static final String NAME = "pan";
}
private static class Dessert {
static final String NAME = "cake";
}
}