Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
Tags
- EntityGraph
- BFS
- 파이썬
- 자바
- JVM
- 배낭문제
- EffectiveJava
- Garbage Collection
- @Transactional
- JPA
- Java
- cache
- collapse
- Spring Security
- 클린아키텍처
- interceptor
- 동시성처리
- 캐시
- AOP
- lombok
- effective java
- TDD
- Transactional
- 이펙티브자바
- 코딩테스트
- 알고리즘
- 멱등성
- thymeleaf
- 타임리프
- spring
Archives
- Today
- Total
Jinnie devlog
[Effective Java] 톱레벨 클래스는 한 파일에 하나만 담으라 본문
- 소스 파일 하나에 톱레벨 클래스를 여러 개 선언하더라도 자바 컴파일러는 불평하지 않는다.
- 하지만 아무런 득이 없을 뿐더러 심각한 위험을 감수해야 하는 행위다.
- 이렇게 하면 한 클래스를 여러 가지로 정의할 수 있으며, 그 중 어느 것을 사용할지는 어느 소스 파일을 먼저 컴파일하냐에 따라 달라지기 때문이다.
톱레벨 클래스를 중복 정의한 경우
Utensil(집기)와 Dessert(디저트)를 참조하는 Main 클래스
public class Main{
public static void main(String[] args){
System.out.println(Utensil.NAME + Dessert.NAME);
}
}
Utensil 파일에 함께 선언된 utensil 클래스와 Dessert 클래스
class Utensil{
static final String NAME = "pan";
}
class Dessert{
static final String NAME = "cake";
}
- Main을 실행하면 pancake을 출력한다.
우연히 똑같은 두 클래스를 담은 Dessert.java 파일을 만들어보자
Dessert 파일에 함께 선언된 Utensil 클래스와 Dessert 클래스
class Utensil{
static final String NAME = "pot";
}
class Dessert{
static final String NAME = "pie";
}
javac Main.java Dessert.java 명령으로 컴파일 한다면,
- 컴파일러는 가장 먼저 Main.java를 컴파일하고
- 그 안에서 Dessert 참조보다 먼저 나오는 Utensil 참조를 만나면
- Utensil.java 파일 안에 있는 Utensil과 Dessert를 모두 찾아낸다.
- 그럼 Dessert.java를 처리할 때 같은 클래스가 이미 정의되었다는 것을 알게된다.
=> 컴파일 오류가 나고 Utensil과 Dessert 클래스를 중복 정의했다고 알려줄 것이다.
javac Main.java 나 javac Main.java Utensil.java 명령으로 컴파일을 한다면,
- Dessert.java 파일을 작성하기 전처럼 pancake을 출력한다.
- 그러나 javac Dessert.java Main.java 명령으로 컴파일하면 potpie를 출력한다.
=> 이처럼 컴파일러에 어느 소스 파일을 먼저 건네느냐에 따라 동작이 달라지므로 반드시 바로잡아야 된다.
해결책: 톱레벨 클래스들(Utensil과 Dessert)을 서로 다른 소스로 분리하면 된다.
- 굳이 여러 톱 레벨 클래스를 한 파일에 담고 싶다면 정적 멤버 클래스(아이템 24)를 사용하는 방법을 고민해볼 수 있다.
- 다른 클래스에 딸린 부차적인 클래스라면 정적 멤버 클래스로 만드는 쪽이 일반적으로 더 나을 것이다.
- 읽기 좋고, private으로 선언하면(아이템 15) 접근 범위도 최소로 관리할 수 있기 때문이다.
톱레벨 클래스를 정적 멤버 클래스로 바꿔본 모습
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 = "cake";
}
}
핵심 정리
- 소스 파일 하나에는 반드시 톱레벨 클래스(혹은 톱레벨 인터페이스)를 하나만 담자
- 이 규칙만 따른다면 컴파일러가 한 클래스에 대한 정의를 여러 개 만들어내는 일은 사라진다.
- 소스 파일을 어떤 순서로 컴파일하든 바이너리 파일이나 프로그램의 동작이 달라지는 일은 결코 일어나지 않을 것이다.
'Java' 카테고리의 다른 글
[Effective Java] 한정적 와일드카드를 사용해 API 유연성을 높이라 (0) | 2023.02.02 |
---|---|
[Effective Java] 로 타입은 사용하지 말라 (0) | 2023.02.02 |
[Effective Java] 추상 클래스보다는 인터페이스를 우선하라 (0) | 2023.02.02 |
[Effective Java] 상속을 고려해 설계하고 문서화하라. 그러지 않았다면 상속을 금지하라 (0) | 2023.02.02 |
[Effective Java] clone 재정의는 주의해서 진행하라 (1) | 2023.02.02 |