Effective Java
[Effective Java] 아이템 25 - 톱레벨 클래스는 한 파일에 하나만 담아라
takman
2022. 2. 14. 14:12
소스 파일 하나에 톱레벨 클래스를 여러개 선언한다면?
자바 컴파일러는 아무런 문제가 없다.
"but" 아무런 득도 없고, 심각한 위험을 감수해야 한다.
문제
※ 한 클래스를 여러 가지로 정의할 수 있으며, 그중 어느 것을 사용하지는 어느 소스 파일을 먼저 컴파일하냐에 따라 달라지기 때문
예시)
Main 클래스 하나를 담고 있고, Main 클래스는 다른 톱레벨 클래스 2개(Utensil과 Dessert)를 참조할 때
public class Main {
public static void main(String[] args) {
System.out.println(Utensil.NAME + Dessert.NAME);
}
}
집기(Utensil)와 디저트(Dessert) 클래스가 Utensil.java 한 파일에 정의되어 있다면?
class Utensil {
static final String NAME = "pan";
}
class Dessert {
static final String NAME = "cake";
}
Main을 실행할 때 pancake를 출력한다.
이 때, 우연히 똑같은 두 클래스를 담은 Dessert.java라는 파일을 만들었다면?
class Utensil {
static final NAME = "pot";
}
class Dessert {
static final NAME = "pie";
}
- 운 좋게 javac Main.java Dessert.java 명령으로 컴파일한다면 컴파일 오류가 나고 Utensil과 Dessert 클래스를 중복 정의했다고 알려준다.
1. 컴파일러는 먼저 Main.java를 컴파일하고, Main.java파일 안에서 가장 먼저 나오는 Utensil 참조를 만나면 Utensil.java 파 일을 찾아 그안에 있는 Utensil과 Dessert를 모두 찾는다.
2. 그 후 컴파일러가 두번째 명령줄 인수인 Dessert.java 처리하려고 할 때, 같은 클래스가 있음을 알아 낸다.
3. 컴파일 오류를 발생 시킴( 클래스를 중복 정의)
- 컴파일러에 어떤 소스를 먼저 제공하느냐에 따라 동작이 달라지는 문제가 발생한다.
javac Main.java 나 javac Main.java Utensil.java 명령으로 컴파일하여 실행하는 경우 의도한 pancake 출력
"but" javac Dessert.java Main.java 명령으로 컴파일하면 potpie를 출력
해결
1. 톱레벨 클래스를 서로 다른 소스 파일로 분리시킨다.
2. 만약 여러 톱레벨 클래스를 한 파일에 담고 싶다면, 정적 멤버 클래스로 만들어라
정적 멤버 클래스로 만들었을 때 장점)
1. 다른 클래스에 딸린 부차적인 클래스라면 정적 멤버 클래스로 만드는 쪽이 일반적으로 낫다.
2. 읽기 좋고, private으로 선언시 접근 범위도 최소로 관리가 가능하다.
위의 예시를 정적 멤버 클래스로 바꾼 경우
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"; } }