들어가며
소스 파일 하나에 톱레벨 클래스를 여러 개 선언하더라도 자바 컴파일러는 불평하지 않는다. 하지만 아무런 득이 없을 뿐더러 심각한 위험이 발생할 수도 있다. 컴파일 순서에 따라 결과가 달라질 수도 있기 때문이다.
예시
// (Page 115)
public class Main {
public static void main(String[] args) {
System.out.println(Utensil.NAME + Dessert.NAME);
}
}
먼저 Main 클래스 하나를 담고있고 Main 클래스는 다른 톱 레벨 클래스 2개 (Utensil, Dessert)를 참조한다.
//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라는 한 파일에 정의되어있을때는 문제가 없다.
// 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으로 선언하면 접근 범위도 최소화 할 수 있기 때문이다.
// 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";
}
}