본문 바로가기
Dev Books/Effective Java

[item 25] 톱레벨 클래스는 한 파일에 하나만 담으라

by Thumper 2024. 6. 17.

이번 포스팅의 요약은 다음과 같다.

1. 한 개의 파일에 한 개의 톱레벨 클래스만 둔다.
2. (한 파일에 여러개를 두고 싶다면) 정적 멤버 클래스 방식을 사용한다.

톱 레벨 클래스

톱 레벨 클래스는 중첩 클래스가 아닌 클래스이다.

중첩 클래스는 "다른 클래스 안에 정의된 클래스"를 말한다. item 24 편에 정리해두었다.

코드

코드를 통해 톱레벨 클래스에 대해 알아보자.

집기(Utensil)와 디저트(Dessert) 클래스가 Utensil.java라는 한 파일에 정의되어 있다,
그리고 Dessert.java 파일에도 집기, 디저트가 정의되어 있다.

무슨 문제가 발생할까?

// Main.java
package study.effectivejava.item25;

public class Main {
    public static void main(String[] args) {
        System.out.println(Utensil.NAME + ", " + Dessert.NAME);
    }
}

// Utensil.java
package study.effectivejava.item25;

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

class Dessert {
    static final String NAME = "cake";
}
// Dessert.java
package study.effectivejava.item25;

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

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

컴파일 오류 발생

위처럼 작성했을 때, 컴파일 오류가 발생한다. Utensil과 Dessert 클래스를 중복 정의했다고 알려줄 것이다.

컴파일러는 가장 먼저 Main.java를 컴파일하고, 그 안에서 먼저 나오는 참조(Utensil, Dessert 중 하나) 살피다가 중복 정의임을 알게 된다.
image


image


image



javac Main.java 명령으로 컴파일했을 때

javac Main.java나 javac Main.java Utensil.java 명령으로 컴파일하면 Dessert.java 파일을 작성하기 전처럼 pancake를 출력한다.
javac main 컴파일


javac Dessert.java Main.java 명령으로 컴파일했을 때

javac Dessert.java Main.java 명령으로 컴파일하면 potpie를 출력한다.
javac Dessertjava Mainjava 컴파일


이처럼 컴파일러에 어느 소스 파일을 먼저 건네느냐에 따라 동작이 달라지므로 반드시 바로 잡아야 할 문제다.

해결책

"톱레벨 클래스들을 서로 다른 소스 파일로 분리"하는 방법이 있다.

// Dessert.java
package study.effectivejava.item25;

class Dessert {
    static final String NAME = "cake";
}
// Utensil.java
class Utensil {
    static final String NAME = "pan";
}



다른 클래스에 딸린 부차적인 클래스라면 정적 멤버 클래스를 사용한다.
아래와 같이 static class로 선언하면 된다.

public class Main {

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

결론

  • 소스 파일 하나에는 반드시 톱레벨 클래스(혹은 톱레벨 인터페이스)를 하나만 담자
  • 터미널을 통해서 javac 명령어를 이용하지 않으면 인텔리제이는 어떤 순서든 컴파일을 해주지 않는다.

댓글