톱레벨 클래스
소스 파일 하나에 톱레벨 클래스를 여러개 선언하더라도 자바 컴파일러는 불평하지 않는다. 하지만 아무런 득이 없고 심각한 위험을 감수해야한다.
어느 소스파일을 먼저 컴파일하느냐에 따라 결과가 달라질 수 있는 위험이 있는데, 이를 예제를 통해 알아보자.
Utensil.java
package com.java.effective.item25;
class Utensil {
static final String NAME = "pan";
}
class Dessert {
static final String NAME = "cake";
}
Main.java
package com.java.effective.item25;
public class Main {
public static void main(String[] args) {
// pancake
System.out.println(Utensil.NAME + Dessert.NAME);
}
}
추가로 우연히 똑같은 두 클래스를 담은 Dessert.java 파일을 생성해보자.
Dessert.java
package com.java.effective.item25;
class Utensil {
static final String NAME = "pot";
}
class Dessert {
static final String NAME = "pie";
}
▶ 컴파일 에러 발생
javac Main.java Dessert.java // 컴파일 오류!
컴파일 에러가 발생한다. 클래스가 중복 정의되었다고 알려준다.
1) Main.java -> Utensil.java -> Dessert.java
System.out.println(Utensil.NAME + Dessert.NAME);
컴파일러는 가장 먼저 Main.java를 컴파일하고, 그 안에서 Utensil 참조가 먼저 나오므로, Utemsil.java 파일을 살펴 Utensil, Dessert 모두 찾아낼 것이다. 그런 다음 Dessert.java 를 처리하려고 할때 같은 클래스의 정의가 있음을 알게된다.
2) "pancake" 결과
javac Main.java
javac Main.java Utensil.java
위 명령어로 컴파일하면 Dessert.java 파일을 작성하기 전처럼 정상적으로 "pancake" 결과를 출력한다.
3) "potpie" 결과
javac Dessert.java Main.java
컴파일러에 어느 소스파일을 먼저 건네느냐에 따라 동작이 달라지게된다. 이는 큰 문제점이다.
해결책
아주 간단하다. 톱레켈 클래스(Utensil.java, Dessert.java)를 서로 다른 소스 파일로 분리하면 된다. 굳이 여러 톱레벨 클래스를 한 파일에 담고싶다면, 정적 멤버 클래스를 사용하는 방법을 고민해봐야한다.
다른 클래스에 딸린 부차적인 클래스라면 정적 멤버 클래스로 만드는 쪽이 더 나을것이다. private 로 선언하면 접근 범위도 최소화하여 관리할 수 있다.
정적 멤버 클래스로 바꾼 Test.java
package com.java.effective.item25;
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";
}
}
'Book > Effective Java' 카테고리의 다른 글
[교재 EffectiveJava] 아이템 27. 비검사 경고를 제거하라 (0) | 2021.10.27 |
---|---|
[교재 EffectiveJava] 아이템 26. 로 타입은 사용하지 말라 (0) | 2021.10.26 |
[교재 EffectiveJava] 아이템 24. 멤버 클래스는 되도록 static으로 만들라 (0) | 2021.10.25 |
[교재 EffectiveJava] 아이템 23. 태그 달린 클래스보다는 클래스 계층구조를 활용하라 (0) | 2021.10.24 |
[교재 EffectiveJava] 아이템 22. 인터페이스는 타입을 정의하는 용도로만 사용하라 (0) | 2021.10.23 |