티스토리 뷰
소스 파일 하나에 톱레벨 클래스를 여러 개 선언하더라도 자바 컴파일러는 불평하지 않습니다.
하지만 아무런 득이 없을 뿐더러 심각한 위험을 감수해야 하는 행위입니다.
이렇게 하면 한 클래스를 여러 가지로 정의할 수 있으며, 그 중 어느 것을 사용할지는 어느 소스 파일을 먼저 컴파일하느냐에 따라 달라지기 때문입니다.
구체적인 예를 봅시다.
다음 소스 파일은 Main 클래스 하나를 담고 있고, Main 클래스는 다른 톱레벨 클래스 2개를 참조합니다.
public class Main {
public static void main(Stirng[] args) {
System.out.println(Utensil.NAME + Dessert.NAME);
}
}
집기(Utensil)와 디저트(Dessert) 클래스가 Utensil.java라는 한 파일에 정의되어 있다고 해봅시다.
class Utensil {
static final String NAME = "pan";
}
class Dessert {
static final String NAME = "cake";
}
물론 Main을 실행하면 "pancake"을 출력합니다.
이제 우연히 똑같은 두 클래스를 담은 Dessert.java라는 파일을 만들었다고 해봅시다.
class Utensil {
static final String NAME = "pot";
}
class Dessert {
static final String NAME = "pie";
}
운 좋게 javac Main.java Dessert.java 명령으로 컴파일한다면 컴파일 오류가 나고 Utensil과 Dessert 클래스를 중복 정의했다고 알려줄 것입니다.
컴파일러는 가장 먼저 Main.java를 컴파일하고, 그 안에서 (Dessert 참조보다 먼저 나오는) Utensil 참조를 만나면 Utensil.java 파일을 살펴 Utensil과 Dessert를 모두 찾아낼 것입니다.
그런 다음 컴파일러가 두 번째 명령줄 인수로 넘어온 Dessert.java를 처리하려 할 때 같은 클래스의 정의가 이미 있음을 알게 됩니다.
한편, javac Main.java나 javac Main.java Utensil.java 명령으로 컴파일하면 Dessert.java 파일을 작성하기 전처럼 pancake를 출력합니다.
그러나 javac Dessert.java Main.java 명령으로 컴파일하면 potpie를 출력합니다.
이처럼 컴파일러에 어느 소스 파일을 먼저 건네느냐에 따라 동작이 달라지므로 반드시 바로 잡아야 할 문제입니다.
다행히 해결책은 아주 간단합니다.
단순히 톱레벨 클래스들(Utensil, Dessert)을 서로 다른 소스 파일로 분리하면 그만입니다.
굳이 여러 톱레벨 클래스를 한 파일에 담고 싶다면 정적 멤버 클래스(아이템 24)를 사용하는 방법을 고려해볼 수 있습니다.
다른 클래스에 딸린 부차적인 클래스라면 정적 멤버 클래스로 만드는 쪽이 일반적으로 더 나을 것입니다.
읽기 좋고, private으로 선언하면 (아이템 15) 접근 범위도 최소로 관리할 수 있기 때문입니다.
다음 코드는 예를 정적 멤버 클래스로 바꿔본 예입니다.
public class Test {
public static void main(Stirng[] 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";
}
}
정리
- 교훈은 명확하다.
- 소스 파일 하나에는 반드시 톱레벨 클래스(혹은 톱레벨 인터페이스)를 하나만 담자.
- 이 규칙만 따른다면 컴파일러가 한 클래스에 대한 정의를 여러 개 만들어 내는 일은 사라진다.
- 소스 파일을 어떤 순서로 컴파일하든 바이너리 파일이나 프로그램의 동작이 달라지는 일은 결코 일어나지 않을 것이다.
'JAVA > 이펙티브 자바' 카테고리의 다른 글
아이템[27]. 비검사 경고를 제거하라 (0) | 2022.04.13 |
---|---|
아이템[26]. 로 타입은 사용하지 말라 (0) | 2022.04.13 |
아이템[24]. 멤버 클래스는 되도록 static으로 만들라 (0) | 2022.04.10 |
아이템[23]. 태그 달린 클래스보다는 클래스 계층구조를 활용하라 (0) | 2022.04.06 |
아이템[22].인터페이스는 타입을 정의하는 용도로만 사용하라 (0) | 2022.04.04 |
- Total
- Today
- Yesterday
- node.js
- 클린 아키텍처
- 백준
- JPA
- Spring
- kkoon9
- kotest
- Effective Java
- 클린 코드
- programmers
- Algorithm
- AWS
- Java
- BOJ
- Olympiad
- BAEKJOON
- 이펙티브 자바
- 코테
- 객체지향
- Spring Boot
- 디자인 패턴
- 프로그래머스
- C++
- 정규표현식
- 디자인패턴
- Kotlin
- 테라폼
- 알고리즘
- MSA
- 이팩티브 자바
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |