소스 파일 하나에는 반드시 톱레벨 클래스(혹은 인터페이스)를 하나만 담자.
* 중첩 클래스는 top level class가 아님
📌 문제 상황
Utensil.java
class UtenSil {
static final String NAME = "pan";
}
class Dessert {
static final String NAME = "cake";
}
Dessert.java
class UtenSil {
static final String NAME = "pot";
}
class Dessert {
static final String NAME = "pie";
}
Main.java
class Main {
public static void main(String[] args) {
System.out.println(Utensil.NAME + Dessert.NAME);
}
}
위는 모두 잘못된 방법이므로 따라하지 말자.
소스 파일 하나에 톱레벨 클래스를 여러 개 선언해봐야 아무런 득도 없다. 오히려 심각한 위험을 감수해야 한다.
운이 좋다면 중복 정의로 컴파일 오류에서 잡아낼 수 있겠지만, 순전히 어느 소스 파일을 먼저 컴파일하느냐에 달렸다.
예컨데, Dessert.java를 만들기 전에 Main을 실행하면 pancake를 정상 출력할 것이다.
그런데 우연히 똑같은 두 클래스를 담은 Dessert.java라는 파일을 만들었다고 쳐보자.
"javac Main.java Dessert.java"는 컴파일 오류에 실패한다. (컴파일러는 Main.java를 컴파일하고, 그 안에서 Dessert 참조보다 먼저 나오는 Utensil 참조를 만나면 Utensil.java를 확인하고, 이후 Dessert.java를 처리할 때 중복 정의를 판단할 것이다.)
하지만 "javac Main.java"나 "javac Main.java Utensil.java"는 여전히 pancake를 출력한다.
"javac Dessert.java Main.java"로 컴파일하면 potpie도 출력한다!
즉, 어느 소스 파일을 먼저 건네느냐에 따라 동작이 달라지기 때문에 바로 잡아야 한다.
📌 해결방안
1. 톱레벨 클래스들을 서로 다른 소스 파일로 분리해라.
2. 굳이 한 파일에 담고 싶다면 정적 멤버 클래스(Item 24)를 사용해라.
class Main {
public static void main(String[] args) {
System.out.println(Utensil.NAME + Dessert.NAME);
}
static class Utensil {
static final String NAME = "pan";
}
static class Dessert {
static final String NAME = "cake";
}
}