정보 은닉의 핵심은 접근제어자
이다.
기본 원칙 : 모든 클래스와 멤버의 접근성을 가능한 좁혀야한다.
그런데, 리스코프 원칙에 부합하기 위해서 하위 클래스는 상위 클래스보다 좁혀질 수 없다는 제약이 있다. 이는 접근성을 좁히지 못하게 방해하는 제약이 된다.
필드가 가변 객체를 참조하거나 final 이 아닌 인스턴스 필드를 public 으로 선언하면 그 필드에 담을 수 있는 값을 제한할 수 없게 된다.
그리고 필드를 수정할 때 다른 작업을 하지 못하기 때문에 스레드 안전하지 못하다. 필드가 final 이면서 불변 객체를 참조하더라도 public 필드를 없애는 방식으로 리팩터링하지 못한다는 문제가 있다.
예외가 있는데, 해당 클래스가 표현하는 추상 개념을 완성하는데 꼭 필요한 구성요소의 상수라면 public static final 필드를 공개해도 좋다.
이런 필드는 반드시 기본 타입이나 불변 객체를 참조해야 한다. 다른 객체를 참조하지 못하지만 참조된 객체는 수정될 수 있기 때문이다.
길이가 0 이 아닌 배열은 모두 변경 가능하기 때문에 조심해야 한다. 클래스에서 public static final 배열 필드를 두거나 이 필드를 반환하는 접근자 메서드를 제공하면 안된다. 이 배열의 내용을 수정할 수 있게 되기 때문이다.
이에 대한 해결책은 두가지다.
private static fianl Thing[] PRIVATE_VALUES = { ... };
public static final List<Thing> VALUES = Collections.unmodifiableList(Arrays.asList(PRIVATE_VALUES));
private static fianl Thing[] PRIVATE_VALUES = { ... };
public static final Thing[] values() {
return PRIVATE_VALUES.clone();
}