DEV ℧ Developer Diary

[EffectiveJava] item25 - 톱레벨 클래스는 한 파일에 하나만 담으라

class 하나당 왜 파일을 하나만 만들까? 모두 당연하게 해왔지만, 왜 이렇게 하는지에 대해 정의해볼까 한다.

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

이렇게 하면 한 클래스가 여러가지로 정의 될 수 있으며, 그 중 어느것을 사용할 지는 어느 소스 파일을 먼저 컴파일 하냐에 따라 달라지기 때문이다.

이는 심각한 오류를 가져올 수 있으며, 객체지향적인 설계가 깨지는 일이다.

아래의 코드가 있다. 아래는 Utensil, Dessert 의 NAME을 가져와 출력하는 코드이다.

public class Main {
    public static void main(String args) {
        System.out.pringln(Utensil.NAME + Dessert.NAME);
    }
}

만약 Utensil 클래스와 Dessert가 하나의 .java 파일에 정의되어있다면 어떻게 될까?

MultipleClass.java

class Utensil {
    static final String NAME = "pan";
}

class Dessert {
    static final String NAME = "cake";
}

하나의 파일에 단 한번씩만 정의되어 있다면 컴파일 오류가 발생하지 않는다.

여기서 Main 클래스를 실행한다면 pancake를 출력한다.

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

MultipleClassTwo.java

class Utensil {
  static final String NAME = "twosome";
}

class Dessert {
  static final String NAME = "coffee";
}

운좋게 javac Main.java MultipleClassTwo.java 명령으로 컴파일한다면 컴파일 오류가나고 Utensil, Dessert 클래스를 중복 정의했다고 알려줄 것이다.

컴파일러는 Main.java를 컴파일 하고, 그 안에서 Dessert 참조보다 먼저나오는 Utensil 참조를 만나면 MultipleClass.java 파일을 살펴 Utensil와 Dessert를 모두 찾아 낼것이다.

그다음 컴파일러가 두번째 명령줄 인수로 넘어온 MultipleClassTwo.java를 처리하려 할때 같은 클래스의 정의가 이미 있음을 알게된다.

한편, javac Main.java나 javac Main.java MultipleClass.java 명령으로 컴파일 하면 MultipleClassTwo.java 파일을 작성하기 전처럼 pancake를 출력한다.

그러나 javac MultipleClass.java Main.java의 순서로 컴파일 하면 twosomecoffee를 출력한다. 이처럼 컴파일러에 어느 소스 파일을 먼저 건네느냐에 따라 동작이 달라지므로 반드시 바로 잡아야할 문제다.

해결책은 간단한다. 두 class인 Utensil와 Dessert 클래스를 다른 자바 파일로 분리하거나, 정적 inner class로 구분하면 될것이다.

MultipleClassThree.java

public class MultipleClassThree {
  static class Utensil {
    static final String NAME = "starbuck";
  }

  static class Dessert {
    static final String NAME = "desert";
  }
}