정보 은닉의 장점
- 시스템 개발 속도를 높인다. (여러 컴포넌트를 병렬로 개발 가능하기 때문)
- 시스템 관리 비용을 낮춘다. (각 컴포넌트를 더 빨리 파악해 디버깅 가능, 교체 부담 적음)
- 성능 최적화에 도움을 준다. (다른 컴포넌트에 영향을 주지 않고 해당 컴포넌트만 최적화할 수 있기 때문)
- 소프트웨어 재사용성을 높인다. (독자적으로 동작하는 컴포넌트는 여러 상황에서 유용함)
- 큰 시스템을 제작하는 난이도를 낮춰준다. (시스템이 완벽하지 않아도 개별 컴포넌트의 동작 검증 가능)
모든 클래스와 멤버의 접근성을 가능한 한 좁혀야 한다
public은 공개 API이기 때문에 하위 호환을 위해 영원히 관리해줘야만 한다.
한 클래스에서만 사용하는 package-private 톱레벨 클래스나 인터페이스는 이를 사용하는 클래스 안에 private static으로 중첩시켜보자 [아이템 24]
public일 필요가 없는 클래스의 접근 수준을 package-private 톱레벨 클래스로 좁히자
4가지 접근 수준 점검~
- private: 멤버를 선언한 톱레벨 클래스에서만 접근할 수 있다.
- package-private: 멤버가 소속된 패키지 안의 모든 클래스에서 접근할 수 있다. 접근 제한자를 명시하지 않았을 때 적용되는 패키지 접근 수준이다. (단, 인터페이스의 멤버는 기본적으로 public이 적용된다).
- protected: package-private의 접근 범위를 포함하며, 이 멤버를 선언한 클래스의 하위 클래스에서도 접근할 수 있다.
- public: 모든 곳에서 접근할 수 있다.
중요해보이는 내용들
멤버 접근성 좁히기: 클래스의 공개 API를 세심히 설계한 후, 그 외의 모든 멤버는 private으로 만들자. 그리고 오직 같은 패키지의 다른 클래스가 접근해야 하는 멤버에 한해 package-private으로 풀어주자.
protected의 멤버 수는 적을수록 좋다.
상위 클래스의 메서드를 재정의할 때 그 접근 수준을 상위 클래스에서보다 좁게 설정할 수 없다는 제약으로 멤버 접근성을 좁히는 것에 방해가 될 때도 있음.
코드를 테스트하려는 목적으로 접근 범위를 넓히는 것은 적당 수준까지 괜찮다.
- public 클래스 내 private 멤버를 package-private까지는 허용가능이나 그 이상은 안 된다.
- 테스트를 위해 클래스, 인터페이스, 멤버를 공개 API로 만들어서는 안 된다.
- 테스트 코드를 테스트 대상과 같은 패키지에 두면 이럴 필요도 없다.
public 클래스의 인스턴스 필드는 되도록 public이 아니어야 한다 [아이템 16]
public 가변 필드를 갖는 클래스는 일반적으로 thread-safe 하지 않다.
클래스에서 public static final 배열 필드를 두거나 이 필드를 반환하는 접근자 메서드를 제공해서는 안 된다.
- 제공하게 된다면 클라이언트에서 그 배열의 내용을 수정할 수 있게 된다. (당연하지;;)
- 필요하다면 2가지 방법이 있지
- 첫번째 방법: 앞 코드의 public 배열을 private으로 만들고 public 불변 리스트를 추가하기
1
2private static final Thing[] PRIVATE_VALUES = { ... };
public static final List<Thing> VALUES = Collections.unmodifiableList(Arrays.asList(PRIVATE_VALUES));- 두번째 방법: 배열을 private으로 만들고 그 복사본을 반환하는 public 메서드를 추가하는 방법 (방어적 복사)
1
2
3
4private static final Thing[] PRIVATE_VALUES = { ... };
public static final Thing[] values() {
return PRIVATE_VALUES.clone();
}모듈 시스템을 활용해서 클래스를 외부에 공개하지 않으면서 같은 모듈을 이루는 패키지 사이에서 자유롭게 공유할 수 있게도 가능함. (protected나 public이라도 module-info.java와 같은 파일에 export하지 않으면)
- 주의할 점: 한 모듈의 JAR 파일을 자신의 모듈 경로가 아닌 애플리케이션 classpath에 두면, 그 모듈 안의 모든 패키지는 마치 모듈이 없는 것처럼 행동한다. (모듈 공개 여부와 상관 없이 public 클래스가 선언한 모든 public 혹은 protected 멤버를 모듈 밖에서도 접근할 수 있게 된다.)
- 대표적 예시가 JDK 그 자체
- 자바 라이브러리에서 공개하지 않은 패키지들은 해당 모듈 밖에서는 절대로 접근할 수 없다.
- 꼭 필요한 게 아니라면 자제하길
핵심 정리
- 프로그램 요소의 접근성은 가능한 한 최소한으로 하라.
- 꼭 필요한 것만 골라 최소한의 public API를 설계하자.
- public 클래스는 상수용 public static final 필드 외에는 어떠한 public 필드도 가져서는 안 된다. 해당 필드가 참조하는 객체가 불변인지 확인하라.