[교재 EffectiveJava] 아이템 25. 톱레벨 클래스는 한 파일에 하나만 담으라

반응형
728x90
반응형

톱레벨 클래스

소스 파일 하나에 톱레벨 클래스를 여러개 선언하더라도 자바 컴파일러는 불평하지 않는다. 하지만 아무런 득이 없고 심각한 위험을 감수해야한다. 

 

어느 소스파일을 먼저 컴파일하느냐에 따라 결과가 달라질 수 있는 위험이 있는데, 이를 예제를 통해 알아보자.

 

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";
    }
}

 

 

반응형

Designed by JB FACTORY