-
[Java] 이펙티브 자바 (3) - 클래스와 인터페이스Java 2020. 4. 18. 11:51반응형
아이템 15. 클래스와 멤버의 접근 권한을 최소화하라
정보 은닉(캡슐화)의 장점
- 시스템 개발 속도를 높임
- 시스템 관리 비용을 낮춤
- 성능을 높여주진 않지만, 성능 최적화에 도움을 줌
- 소프트웨어 재사용성을 높임
- 큰 시스템을 제작하는 난이도를 낮춰줌
자바 정보 은닉의 핵심 - 접근 제한자
- 접근 제한자를 제대로 활용하는 것이 정보 은닉의 핵심. 기본 원칙 - 모든 클래스와 멤버의 접근성을 가능한 한 좁혀야 함
- public 클래스에서 멤버의 접근 수준을 protected 또는 public으로 변경시, 공개 API가 되므로 영원히 지원해야 함(유지보수) -> 클래스의 공개 API를 세심히 설계 후, 그 외 모든 멤버는 private로 만들고, 같은 패키지에서 접근해야 한다면 package-private으로 풀어주기
- 상위 클래스의 메서드를 재정의할 때는 그 접근 수준을 상위 클래스에서보다 좁게 설정할 수 없으므로 유의
- 테스트만을 위해 클래스, 인터페이스, 멤버를 공개 API로 만들지 말 것(테스트 코드를 테스트 대상과 같은 패키지에 두고 package-private로 풀어주는 것은 허용)
접근 제한자 종류
- private : 멤버를 선언한 톱레벨 클래스에서만 접근할 수 있음
- package-private(default) : 멤버가 소속된 패키지 안의 모든 클래스에서 접근할 수 있음, 클래스에서 접근 제한자를 명시하지 않았을 때 적용됨
- protected : package-private 접근 범위를 포함하며, 이 멤버를 선언한 클래스에서도 접근 가능
- public : 모든 곳에서 접근 가능
public 클래스의 인스턴스 필드는 되도록 public이 아니여야 함
- public 가변 필드를 갖는 클래스는 일반적으로 쓰레드 안전하지 않음
- 필드가 final이면서 불변 객체를 참조하더라도, 내부 구현을 바꾸고 싶을 때 public 필드를 없앨 수 없음
- 추상 개념을 완성하는 데 꼭 필요한 구성요소로써의 상수라면 public static final 필드로 공개 가능
- 단, 배열 필드를 두거나 해당 필드를 반환하는 접근자 메서드를 제공해서는 안 됨(수정 가능)
- 수정 불가한 배열을 필드로 지정하거나, 복사본을 반환하는 메서드를 추가(방어적 복사)
아이템 16. public 클래스에서는 public 필드가 아닌 접근자 메서드를 사용하라
인스턴스 필드들을 모아놓는 일 외에는 아무 목적도 없는(메서드) 퇴보한 클래스
- public 클래스에 public 인스턴스 변수들만 있는 경우
- 데이터 필드에 직접 접근할 수 있으므로 캡슐화의 이점을 제공하지 못함
- API를 수정하지 않고서는 내부 표현을 바꿀 수 없음 - 사용하는 사용자들이 있으므로 필드를 바꾸기 어려움
- 불변식을 보장할 수 없음(그나마 final이면 보장 가능)
- 외부에서 필드에 접근할 때 부수 작업을 수행할 수 없음
public 클래스
- 필드를 모두 private으로 바꾼 후, public 접근자를 추가
- 접근자를 제공함으로써 클래스 내부 표현 방식을 언제든 바꿀 수 있는 유연성을 가짐
package-private 클래스, prviate 중첩 클래스
- 데이터 필드를 노출하더라도 문제가 없음
- 종종 필드를 노출하는 편이 나을 때도 있음
아이템 17. 변경 가능성을 최소화하라
불변 클래스
- 인스턴스의 내부 값을 수정할 수 없는 클래스
- 불변 인스턴스에 간직된 정보는 고정되어 객체가 파괴되는 순간까지 절대 달라지지 않음
- 가변 클래스보다 설계, 구현, 사용이 쉬우며 오류가 생길 여지도 적고 훨씬 안전함
- 클래스는 꼭 필요한 경우가 아니라면 불변이어야 함
- 불변으로 만들 수 없는 클래스라도 변경할 수 있는 부분을 최소한으로 줄일 것
불변 클래스를 만드는 다섯 가지 규칙
- 객체의 상태를 변경하는 메서드(변경자)를 제공하지 않음
- 클래스를 확장할 수 없도록 함
- 모든 필드를 final로 선언함
- 모든 필드를 private으로 선언함
- 자신 외에는 내부의 가변 컴포넌트에 접근할 수 없도록 함
불변 클래스의 장점
- 단순함 : 생성된 시점의 생태를 파괴할 때까지 그대로 간직
- 모든 생성자가 클래스 불변식(class invariant)을 보장한다면 그 클래스를 사용하는 프로그래머가 다른 노력을 들이지 않아도 영원히 불변으로 남음
- 쓰레드 안전하여 따로 동기화할 필요가 없음 -> 안심하고 공유할 수 있음
- 방어적 복사가 필요하지 않음 -> clone 메서드나 복사 생성자를 제공하지 않는 것이 좋음
- 자유롭게 공유할 수 있고, 불변 객체끼리는 내부 데이터를 공유할 수 있음
- 객체를 만들 때 다른 불변 객체들을 구성요소로 사용하면 이점이 많음
- 실패 원자성을 제공
- 불변 클래스의 캐싱
- 불변 클래스라면 한번 만든 인스턴스를 최대한 재활용하는 것이 좋음
- 자주 사용되는 인스턴스를 캐싱하여 같은 인스턴스를 중복 생성하지 않게 해주는 적정 팩터리를 제공할 수 있음
불변 클래스의 단점
- 값이 다르다면 반드시 독립된 객체로 만들어야 함 -> 가짓수가 많다면 큰 비용을 치러야 함
- 대응방법. 다단계 연산(multistep operation)을 예측하여 기본 기능으로 제공하는 방법 - 가변 동반 클래스(companion class)를 이용 -> String의 가변 동반 클래스 - StringBuilder
클래스를 상속하지 못하게 하는 방법
1. final 클래스로 선언
2. 모든 생성자를 private 또는 package-private으로 만들고 public 정적 팩터리를 제공
- 1번 방법보다 훨씬 유연함
불변 클래스의 생성자
- 불변식 설정이 모두 완료된, 초기화가 완벽히 끝난 상태의 객체를 생성해야 함
용어
Failure Atomicity(실패 원자성) : 메서드에서 예외가 발생한 후에도 그 객체는 여전히 메서드 호출 전과 똑같은 유효한 상태여야한다는 성질
아이템 18. 구현 상속보다는 컴포지션을 사용하라
구현 상속
- 상속은 코드를 재사용하는 강력한 수단이지만 항상 최선은 아님
- 상위 클래스와 하위 클래스가 모두 같은 프로그래머가 통제하는 패키지 안에서라면 상속도 안전
- 확장할 목적으로 설계되었고, 문서화가 잘 된 클래스도 마찬가지로 안전
- 다른 패키지의 구체 클래스를 상속하는 일은 위험
- 하위 클래스가 상위 클래스의 '진짜' 하위 타입인 상황에서만 쓰여야 함
- 클래스 B가 클래스 A와 is-a 관계일 때(B는 A인가)만 A를 상속해야 함 - 아니라면 컴포지션!
구현 상속의 단점
- 메서드 호출과 달리 상속은 캡슐화를 깨뜨림
- 상위 클래스가 어떻게 구현되느냐에 따라 하위 클래스의 동작에 이상이 생길 수 있음
- 상위 클래스는 릴리스마다 내부 구현이 달라질 수 있음
- 상위 클래스의 메서드를 재정의하는 경우
- 자신의 다른 부분을 사용하는 자기사용(self-use) 여부는 해당 클래스의 내부 구현 방식이므로 알 수 없고, 예상치못한 결과를 초래함
- 상위 클래스의 메서드를 다시 구현하는 방식 : 시간이 더 들고, 자칫 오류를 내거나 성능을 떨어뜨릴 수 있고, 하위 클래스에서 접근할 수 없는 private 필드를 써야 한다면 불가능
- 새로운 메서드를 추가하더라도, 위험이 전혀 없는 것은 아님
- 하위 클래스에 추가한 메서드와 우연히 새 메서드가 시그니처가 같고 반환 타입이 다르면 컴파일이 안 됨
- 우연히 같다하더라도 상위 클래스의 메서드가 요구하는 규약을 만족하지 못할 가능성이 큼
컴포지션(composition; 구성)
기존 클래스를 확장하는 대신, 새로운 클래스를 만들고 private 필드로 기존 클래스의 인스턴스를 참조
-> 기존 클래스가 새로운 클래스의 구성요소로 쓰인다는 뜻에서 컴포지션이라고 함
- 전달(forwarding) : 새 클래스의 인스턴스 메서드들은 (private로 참조하는) 기존 클래스의 대응하는 메서드를 호출해 결과를 반환, 새 클래스의 메서드들을 전달 메서드(forwarding method)라 부름
컴포지션과 전달의 조합
넓은 의미의 위임(delegation)
엄밀히 따지면 래퍼 객체가 내부 객체에 자기 자신의 참조를 넘기는 경우만 위임에 해당
래퍼 클래스(Wrapper Class)
다른 인스턴스를 감싸고(wrap) 있다는 뜻에서 컴포지션을 사용하는 클래스
- 다른 기능을 덧씌울 경우 데코레이터 패턴에 해당
장점) 하위 클래스보다 견고하고 강력함
단점이 아닌 부분) 전달 메서드가 성능에 주는 영향이나 래퍼 객체가 메모리 사용량에 주는 영향 - 별 다른 영향이 없음
단점) 래퍼 클래스는 콜백(callback) 프레임워크와는 어울리지 않음(SELF 문제)
- 콜백 프레임워크에서는 자기 자신의 참조를 다른 객체에 넘겨서 다음 호출(콜백) 때 사용
- 내부 객체는 자신을 감싸고 있는 래퍼의 존재를 모르니 대신 자신(this)의 참조를 넘기고, 콜백 때는 래퍼가 아닌 내부 객체를 호출
용어
구현 상속 : 클래스가 다른 클래스를 확장하는 상속
인터페이스 상속 : 클래스가 인터페이스를 구현하거나, 인터페이스가 다른 인터페이스를 확장
아이템 19. 상속을 고려해 설계하고 문서화하라. 그렇지 않았다면 상속을 금지하라
클래스를 상속용으로 설계하려면
엄청난 노력이 들고, 제약도 상당함
문서화
상속용 클래스는 재정의할 수 있는 메서드들을 내부적으로 어떻게 이용하는지(자기사용) 문서로 남겨야 함
- 메서드 주석에 @implSpec 태그를 붙여주면 자바독 도구가 "Implementation Requirements"로 시작되는 메서드의 내부 동작 방식을 설명하는 곳을 생성해줌
클래스의 내부 동작 과정 중간에 끼어들 수 있는 훅(hook)을 잘 선별하여 protected 메서드 형태로 공개해야 할 수도 있음
상속용 클래스를 테스트하는 방법
직접 하위 클래스를 만들어보는 것이 '유일'
상속용으로 설계한 클래스는 배포 전 반드시 하위 클래스를 만들어서 검증해야 함
상속을 허용하는 클래스가 지켜야 할 제약
- 직접적으로든 간접적으로든 재정의 가능 메서드를 호출해서는 안 됨
- Cloneable과 Serializable 인터페이스 중 하나라도 구현할 클래스를 상속할 수 있게 설계하는 것은 일반적으로 좋지 않음
- clone과 readObject 메서드는 생성자와 비슷한 효과 (새로운 객체를 만듦) - 모두 직접적으로든 간접적으로든 재정의 가능 메서드를 호출해서는 안됨
- Serializable을 구현한 상속용 클래스가 readResolve나 writeReplace 메서드를 갖는다면, 해당 메서드들은 protected로 선언해야 함 - private은 하위 클래스에서 무시되기 때문
일반 구체 클래스의 상속
- 클래스의 변화가 생길 때마다 하위 클래스를 오동작하게 만들 수 있음
- 상속용으로 설계하지 않은 클래스는 상속을 금지하는 것이 좋음
- 구체 클래스가 표준 인터페이스를 구현하지 않아서 (편의상) 상속을 꼭 허용해야 한다면?
- 클래스 내부에서 재정의 가능 메서드를 사용하지 않게 만들고 문서화
- 재정의 가능 메서드를 호출하는 자기 사용 코드를 완벽히 제거 > 상속해도 위험하지 않은 클래스
- 클래스의 동작을 유지하면서 재정의 가능 메서드를 사용하는 코드를 제거할 수 있는 기계적인 방법
- 각각의 재정의 가능 메서드 -> 자신의 본문 코드를 private '도우미 메서드'로 옮김
- 재정의 가능 메서드를 호출하는 모든 코드들을 해당 도우미 메서드를 직접 호출하도록 변경
아이템 20. 추상 클래스보다는 인터페이스를 우선하라
자바 8 이후의 추상 클래스 vs 인터페이스
자바가 제공하는 다중 구현 메커니즘은 인터페이스와 추상 클래스 두 가지
자바 8부터 인터페이스도 디폴트 메서드(default method)를 제공할 수 있게 되어 두 메커니즘 모두 인스턴스 메서드를 구현 형태로 제공할 수 있음
가장 큰 차이 : 추상 클래스가 정의한 타입을 구현하는 클래스는 반드시 추상 클래스의 하위 클래스가 되어야 함
인터페이스 사용의 장점
- 기존 클래스에도 손쉽게 새로운 인터페이스를 구현해넣을 수 있음
- 믹스인(mixin) 정의에 안성맞춤
- 계층 구조가 없는 타입 프레임워크를 만들 수 있음
- 래퍼 클래스 관용구와 함께 사용시 기능을 향상시키는 안전하고 강력한 수단이 됨
인터페이스의 디폴트 메서드
- 인터페이스의 메서드 중 구현 방법이 명백한 것이 있다면, 그 구현을 디폴트 메서드로 제공해 프로그래머의 일감을 덜 수 있음 => 단 @implSpec 자바독 태그로 문서화
- 제약
- equals와 hashCode 같은 Object의 메서드는 디폴트 메서드로 제공해서는 안 됨
- 인터페이스는 인스턴스 필드를 가질 수 없고, public이 아닌 정적 멤버도 가질 수 없음(private 정적 메서드 예외)
- 직접 만든 인터페이스가 아닌 경우 디폴트 메서드를 추가할 수 없음
인터페이스와 추상 클래스의 조합 -> 템플릿 메서드 패턴
- 인터페이스와 추상 골격 구현(skeletal implementation) 클래스를 함께 제공하는 식으로 인터페이스와 추상 클래스의 장점을 모두 취하는 방법이 있음
- 인터페이스로는 타입을 정의, 필요할 경우 디폴트 메서드 몇 개도 같이 제공, 골격 구현 클래스는 나머지 메서드들까지 구현
- 단순히 골격 구현을 확장하는 것만으로 해당 인터페이스를 구현하는데 필요한 일들이 대부분 완료됨
- 관례상 인터페이스 이름이 Interface라면, 골격 구현 클래스 이름은 AbstractInterface로 명명
- 골격 구현 클래스의 아름다움 : 추상 클래스처럼 구현을 도와주는 동시에, 추상 클래스로 타입을 정의할 때 따라오는 심각한 제약에서 자유로움
시뮬레이트한 다중 상속(simulated multiple inheritance)
- 다중 상속의 많은 장점을 제공하는 동시에 단점은 피하게 해줌
- 골격 구현 클래스를 우회적으로 이용
- 인터페이스를 구현한 클래스에서 골격 구현을 확장한 private 내부 클래스를 정의하고, 각 메서드 호출을 내부 클래스의 인스턴스에 전달(래퍼 클래스와 비슷)
단순 구현(simple implementation)
골격 구현의 작은 변종, 골격 구현과 같이 상속을 위해 인터페이스를 구현했지만 추상 클래스가 아님
동작하는 가장 단순한 구현 - 그대로 써도 되고, 필요에 맞게 확장해도 됨
용어
mixin(믹스인) : 클래스가 구현할 수 있는 타입, 믹스인을 구현한 클래스에 원래의 '주된 타입' 외에도 특정 선택적 행위를 제공한다고 선언하는 효과. 주된 기능에 선택적 기능을 혼합(mix-in)한다고 하아여 믹스인이라 부름
Combiantorial Explosion(조합 폭발) : 클래스 계층구조를 만들 때, 속성이 n개일 경우 지원해야 할 조합의 수는 2^n = 많아질 수록 고도비만 계층구조가 만들어짐
아이템 21. 인터페이스는 구현하는 쪽을 생각해 설계하라
새로운 인터페이스의 디폴트 메서드
- 표준적인 메서드 구현을 제공하는데 아주 유용
- 인터페이스를 더 쉽게 구현해 활용할 수 있도록 함
기존 인터페이스에서의 디폴트 메서드
- 생각할 수 있는 모든 상황에서 불변식을 해치지 않는 디폴트 메서드를 작성하기란 어려움
- (컴파일에 성공하더라도) 기존 구현체에 런타임 오류를 일으킬 수 있음
- 기존 인터페이스에 디폴트 메서드로 새 메서드를 추가하는 일은 꼭 필요한 경우가 아니면 피해야 함
- 인터페이스로부터 메서드를 제거하거나 기존 메서드의 시그니처를 수정하는 용도가 아님
인터페이스 설계
- 디폴트 메서드라는 도구가 생겼지만, 여전히 세심한 주의를 기울여야 함
- 디폴트 메서드로 기존 인터페이스에 새로운 메서드를 추가하면 위험이 딸려옴
- 새로운 인터페이스라면 릴리즈 전에 반드시 테스트를 거쳐야 함
- 인터페이스를 릴리즈한 후라도 결함을 수정하는 게 가능한 경우도 있지만, 절대 그 가능성에 기대서는 안 됨
아이템 22. 인터페이스는 타입을 정의하는 용도로만 사용하라
인터페이스 용도 : 타입 정의
- 자신을 구현한 클래스의 인스턴스를 참조할 수 있는 타입 역할
- 클래스가 어떤 인터페이스를 구현한다는 것 : 자신의 인스턴스로 무엇을 할 수 있는지를 클라이언트에게 얘기해주는 것
상수 인터페이스 안티 패턴 - 사용 금지
- 메서드 없이, 상수를 뜻하는 static final 필드로만 가득 찬 인터페이스
- 인터페이스를 잘못 사용한 예 - 클래스 내부에서 사용하는 상수는 외부 인터페이스가 아닌 내부 구현에 해당
-> 상수 인터페이스 구현은 내부 구현을 클래스의 API로 노출하는 행위
- 상수를 공개할 목적이라면
- 특정 클래스나 인터페이스와 강하게 연관된 상수라면 그 클래스나 인터페이스 자체에 추가
- 열거 타입으로 나타내기 적합한 상수라면 열거 타입으로 만들어 공개
- 둘 다 아니라면 인스턴스화할 수 없는 유틸리티 클래스에 담아서 공개
아이템 23. 태그 달린 클래스보다는 클래스 계층 구조를 활용하라
태그 달린 클래스
- 태그 필드로 현재 상태를 표현하고, 해당 상태에 따라 생성자와 행위가 각각 다름
- 두 가지 이상의 의미를 표현할 수 있으며, 그 중 현재 표현하는 의미를 태그 값으로 알려주는 클래스
- 클래스 계층구조를 어설프게 흉내낸 아류
- 장황하고, 오류를 내기 쉽고, 비효율적
- 태그 필드가 클래스에 있다면, 태그를 없애고 계층 구조로 대체(또는 리팩터링)하는 방법을 생각
클래스 계층 구조의 장점(태그 달린 클래스에 비하여)
- 간결하고 명확, 쓸데없는 코드가 모두 사라짐
- 각 클래스의 생성자가 모든 필드를 남김없이 초기화하고 추상 메서드를 모두 구현했는지 컴파일러가 확인
- 실수로 빼먹은 case문 때문에 런타임 오류가 발생할 일도 없음
- 루트 클래스의 코드를 건드리지 않고도 다른 프로그래머들이 독립적으로 계층 구조를 확장하고 함께 사용할 수 있음
- 타입이 의미별로 따로 존재하므로 변수의 의미를 명시하거나 제한할 수 있고, 특정 의미만 매개변수로 받을 수 있음
- 타입 사이의 자연스러운 계층 관계를 반영할 수 있어서 유연성은 물론 컴파일타임 타입 검사 능력을 높여줌
아이템 24. 멤버 클래스는 되도록 static으로 만들라
중첩 클래스
- 자신을 감싼 바깥 클래스에서만 쓰여야 하며, 그 외의 쓰임새가 있다면 톱레벨 클래스로 만들어야 함
중첩 클래스의 종류
- 정적 멤버 클래스
- (비정적) 멤버 클래스 - 내부 클래스(inner class)
- 익명 클래스 - 내부 클래스(inner class)
- 지역 클래스 - 내부 클래스(inner class)
정적 멤버 클래스
- 다른 클래스 안에 선언, 바깥 클래스의 private 멤버에도 접근 가능 그 외에는 일반 클래스와 동일
- 다른 정적 멤버와 같은 접근 규칙을 적용
-> private으로 선언시 바깥 클래스에서만 접근 = 흔히 바깥 클래스가 표현하는 개겣의 한 부분(구성요소)을 나타낼 때 씀
- 흔히 바깥 클래스와 함께 쓰일 때만 유용한 public 도우미 클래스로 쓰임
- 개념상 바깥 인스턴스와 독립적으로 존재할 수 있다면 정적 멤버 클래스로 만들어야 함
- 바깥 인스턴스에 접근할 일이 없다면 무조건 정적 멤버 클래스로 만들기
(비정적) 멤버 클래스 - 내부 클래스(inner class)
- 정적 멤버 클래스와 달리 바깥 클래스의 인스턴스와 암묵적으로 연결됨
- 인스턴스 메서드에서 정규화된 this를 사용해 바깥 인스턴스의 메서드를 호출하거나 참조를 가져올 수 있음
- 바깥 인스턴스 없이는 생성할 수 없음
- 바깥 인스턴스와의 관계는 멤버 클래스가 인스턴스화될 때 확립되며, 변경할 수 없음
- 보통 바깥 클래스의 인스턴스 메서드에서 비정적 멤버 클래스의 생성자를 호출할 때 자동으로 만들어짐
- 드물게 바깥인스턴스의클래스.new MemberClass(args)를 통해 수동으로 만들기도 함
- 관계 정보는 비정적 멤버 클래스의 인스턴스 안에 만들어져 메모리 공간을 차지, 생성 시간도 더 걸림
- 가비지 컬렉션이 바깥 클래스의 인스턴스를 수거하지 못하는 메모리 누수가 생길 수 있음
- 어댑터를 정의할 때 자주 쓰임
익명 클래스 - 내부 클래스(inner class)
- 이름이 없는 클래스
- 바깥 클래스의 멤버가 아님. 쓰이는 시점에 선언과 동시에 인스턴스가 만들어짐
- 코드의 어디서든 만들 수 있음
- 비정적인 문맥에서 사용될 때만 바깥 클래스의 인스턴스를 참조할 수 있음
- 정적 문맥에서라도 상수 변수 이외의 정적 멤버는 가질 수 없음
- 상수 표현을 위해 초기화된 final 기본 타입과 문자열 필드만 가질 수 있음
- 응용하는데 제약이 많음
- 선언한 지점에서만 인스턴스를 만들 수 있음
- instanceof 검사나 클래스의 이름이 필요한 작업을 수행할 수 없음
- 여러 인터페이스를 구현할 수 없고, 인터 페이스를 구현하는 동시에 다른 클래스를 상속할 수도 없음
- 익명 클래스를 사용하는 클라이언트는 익명 클래스가 상위 타입에서 상속한 멤버 외에는 호출할 수 없음
- 표현식 중간에 등장하므로 (10줄 이하로) 짧지 않으면 가독성이 떨어짐
- 사용하는 경우
- 람다를 지원하기 전 : 즉석에서 작은 함수 객체나 처리 객체(process object)를 만드는 데 주로 사용
- 정적 팩터리 메서드를 구현할 때
지역 클래스 - 내부 클래스(inner class)
- 네 가지 중첩 클래스 중 가장 드물게 사용
- 지역변수를 선언할 수 있는 곳이면 실질적으로 어디서든 선언할 수 있고, 유효 범위도 지역변수와 같음
- 멤버 클래스처럼 이름이 있고 반복해서 사용할 수 있음
- 익명 클래스처럼 비정적 문맥에서 사용될 때만 바깥 인스턴스를 참조할 수 있음
- 정적 멤버는 가질 수 없음
- 가독성을 위해 짧게 작성해야 함
용어
중첩 클래스(nasted class) : 다른 클래스 안에 정의된 클래스
정규화된 this : 클래스명.this 형태로 바깥 클래스의 이름을 명시하는 용법
아이템 25. 톱레벨 클래스는 한 파일에 하나만 담으라
소스 하나에 반드시 톱레벨 클래스 또는 톱레벨 인터페이스를 여러개 담는 경우
- 컴파일러가 한 클래스에 대한 정의를 여러개 만들어 냄
- 소스 파일을 어떤 순서로 컴파일 하는지에 따라 바이너리 파일이나 프로그램의 동작이 달라짐
소스 하나에는 반드시 톱레벨 클래스 또는 톱레벨 인터페이스를 하나만 담기
- 톱레벨 클래스를 서로 다른 소스 파일로 분리
- 여러 톱레벨 클래스를 한 파일에 담고 싶다면 정적 멤버 클래스를 사용하는 방법을 고민
- 다른 클래스에 딸린 부차적인 클래스라면 정적 멤버 클래스로 만드는 쪽이 일반적으로 더 나음 => 읽기 좋고, private으로 선언시 접근 범위도 최소로 관리할 수 있기 때문
반응형'Java' 카테고리의 다른 글
[Java] 이펙티브 자바 (4) - 제네릭 (0) 2020.04.18 [Java] 이펙티브 자바 (2) - 모든 객체의 공통 메서드 (0) 2020.04.18 [Java] 이펙티브 자바 (1) - 객체 생성과 파괴 (0) 2020.04.18 [Java] GOF 디자인패턴 용어 정리 (0) 2020.04.16 자바의 I/O (0) 2020.03.13