티스토리 뷰

(Effective Java) 규칙25. 톱레벨 클래스는 한 파일에 하나만 담으라


소스 파일 하나에 여러 클래스 선언


  • 소스 파일 하나에 톱레벨 클래스를 여러 개 선언하더라도 자바 컴파일러는 불평하지 않는다.
  • 다만, 아무런 득이 없을 뿐더러 심각한 위험을 감수해야 하는 행위다.
    • 한 클래스를 여러 가지로 정의할 수 있으며, 그중 어느 것을 사용할지는 어느 소스 파일을 먼저 컴파일하냐에 따라 달라지기 때문

 

문제 상황


  • 아래 소스 파일은 Main클래스 하나를 담고 있고, 다른 톱레벨 클래스는 다른 톱레벨 클래스 2개(UtensilDessert)를 참조한다.

    public class Main {
        public static void main(String[] args) {
            System.out.println(Utensi.NAME + Dessert.NAME);
        }
    }
    • 집기 (Utensil)와 디저트(Dessert) 클래스가 Utensil.java라는 한 파일에 정의 되어 있다고 해보자

      class Utemsil {
          static final String NAME = "pan";
      }
      
      class Dessert {
          static final String NAME = "cake";
      }
    • 물론 Main을 실행하면"pancake"를 출력함

  • 만약 우연히 똑같은 두 클래스를 담은 Dessert.java라는 파일을 만들었다고 해보자.

    class Utemsil {
        static final String NAME = "pot";
    }
    
    class Dessert {
        static final String NAME = "pie";
    }
  • 운 좋게 javac Main.java Dessert.java 명령으로 컴파일한다면 컴파일 오류가 나면서 UtensilDessert 클래스를 중복 정의했다고 알려줄 것이다.

    • 컴파일러는 먼저 Main.java를 컴파일 하고 그 안에서(Dessert 참조보다 먼저 나오는) Utensil참조를 만나면 Untensil.java 파일을 살펴 UtensilDessert를 모두 찾아낼 것임
    • 후 컴파일러가 두 번째 명령줄 인수인 Dessert.java를 처리하여 할 때 같은 클래스가 이미 있음을 알게 됨
  • 컴파일러에 어떤 소스를 먼저 건네느냐에 따라 동작이 달라지는 문제가 생긴다.

    • javac Main.javajavac Main.java Utensil.java 명령으로 실행하면 의도한 pancake를 출력함
    • 그러나 javac Dessert.java Main.java 명령으로 컴파일 하면 potpie를 출력함

 

해결책


  • 단순히 톱레벨 클래스들(UtensilDessert)을 서로 다른 소스 파일로 분리하면 그만이다.

  • 굳이 여러 톱레벨 클래스를 한 파일에 담고 싶다면 정적 멤버 클래스(규칙 24)를 사용하는 방법을 고민해볼 수 있다.

    • 다른 클래스에 딸린 부차적인 클래스라면 정적 멤버 클래스로 만드는 쪽이 일반적으로 더 나을 것임
    • 읽기 좋고, private으로 선언하면 (규칙 15)접근 범위도 최소로 관리할 수 있기 때문
  • 위 예제를 정적 멤버 클래스로 바꿔본 예제

    public class Main {
        public static void main(String[] args) {
            System.out.println(Utensi.NAME + Dessert.NAME);
        }
    
        private static class Utensil {
            static final String NAME = "pan";
        }
    
        private static class Dessert {
            static final String NAME = "cake";
        }
    }

 

결론


  • 소스 파일 하나에는 반드시 톱레벨 클래스(혹인 톱레벨 인터페이스)를 하나만 담자.

    • 이 규칙만 따른다면 컴파일러가 한 클래스에 대한 정의를 여러 개 만들어 내는 일은 사라짐

끝으로

이 글이 도움이 되었다면, 하단의 Google 광고 👎👎👎 한번씩 클릭 부탁 드립니다. 🙏🙏🙏

광고 클릭은 많은 힘이 됩니다! 

반응형
댓글