잘 설계된 컴포넌트는 클래스 내부 데이터와 내부 구현 정보를 외부 컴포넌트로부터 얼마나 잘 숨겼느냐다.
잘 설계된 컴포넌트는 모든 내부 구현을 완벽히 숨겨, 구현과 API를 깔끔히 분리한다.
오직 API를 통해서만 다른 컴포넌트와 소통하며 서로의 내부 동작 방식에는 전혀 개의치 않는다.
그렇기에 모든 클래스와 멤버의 접근성을 가능한 한 좁혀야 한다.
달리 말하면, 소프트웨어가 올바로 동작하는 한 항상 가장 낮은 접근 수준을 부여해야 한다.
따라서 패키지 외부에서 쓸 이유가 없다면 package-private로 선언하자.
그러면 이들은 API가 아닌 내부 구현이 되어 언제든 수정할 수 있다.
반면, public으로 선언한다면 API가 되므로 하위 호환을 위해 관리해 주어야 한다.
또 한 클래스에서만 사용하는 package-private 톱 레벨 클래스나 인터페이스는 이를 사용하는 클래스 안에 private static으로 중첩하는 것도 좋은 방법이다.
그렇게 하면 중첩된 클래스는 바깥 클래스 하나에서만 접근할 수 있다.
그런데 멤버 접근성을 좁히지 못하게 방해하는 제약이 하나 있다.
상위 클래스의 메서드를 재정의할 때는 그 접근 수준을 상위 클래스에서보다 좁게 설정할 수 없다는 것이다.
그리고 public 클래스의 인스턴스 필드는 되도록 public이 아니어야 한다.
필드가 가변 객체를 참조하거나, final이 아닌 인스턴스 필드를 public으로 선언하면 그 필드에 담을 수 있는 값을 제한할 힘을 잃게 된다.
그 필드와 관련된 모든 것은 불변식을 보장할 수 없게 된다는 뜻이다.
여기에 더해, 필드가 수정될 때 다른 작업을 할 수 없게 되므로 public 가변 필드를 갖는 클래스는 일반적으로 스레드 세이프 하지 않다.
이는 정적 필드에서도 마찬가지다.
하지만 해당 클래스가 표현하는 추상 개념을 완성하는 데 꼭 필요한 구성요소로써의 상수라면 public static final 필드로 공개해도 좋다.
하지만 public static final 배열 필드를 두거나 이 필드를 반환하는 접근자 메서드를 제공해서는 안 된다.
추가로 관례상 상수의 이름을 대문자 알파벳으로써며, 각 단어 사이에 밑줄(_)을 넣는다. Ex) STATIC_FIELD