18. 상속보다는 컴포지션을 사용하라상속상속은 코드를 재사용하는 강력한 수단이지만, 항상 최선은 아니다.잘못 사용하면 오류를 내기 쉬운 소프트웨어를 만들게 된다.상속이 안전할 때상위 클래스와 하위 클래스가 모두 같은 패키지이다.확장할 목적으로 설계되었고 문서화도 잘 된 클래스이다.다른 패키지의 구체 클래스를 상속하는 것은 위험하다.내부 구현을 잘 알지 못하고 오버라이드할 수 있다.내부 구현이 변경되었을때 외부 패키지의 상속받은 클래스가 적절히 알지 못할 수 있다.여기서 말하는 상속은 구현 상속을 말하며, 인터페이스 상속과는 무관하다. 메서드 호출과 달리 상속은 캡슐화를 깨뜨린다.상위 클래스가 어떻게 구현되냐에 따라 하위 클래스의 동작에 이상이 생길 수 있다.상위 클래스는 릴리즈마다 내부 구현이 달라질 수..
17. 변경 가능성을 최소화하라 불변 클래스인스턴스의 내부 값을 수정할 수 없는 클래스String, 내부 값으로 박싱된 클래스들, BigInteger, BigDecimal....블변 클래스는 가변 클래스보다 설계하고 구현하고 사용하기 쉬우며, 오류가 생길 여지도 적고 훨씬 안전하다. 불변 클래스로 만드는 방법1. 객체의 상태를 변경하는 메서드(변경자-setter)를 제공하지 않는다.2. 클래스를 확장할 수 없도록 한다. (final 클래스)하위 클래스에서 상위 클래스의 불변 조건을 깨뜨릴 수 있다.하위 클래스에서 가변 필드를 추가하거나 오버라이드하여 불변성을 해칠 수 있다.3. 모든 필드를 final로 선언한다.4. 모든 필드를 private으로 선언한다.외부에서 접근하지 못하게 하면 내부 구현 변경시에..
public 클래스에서는 public 필드가 아닌 접근자 메서드를 사용하라.public 인스턴스 필드만 모아놓은 클래스는 캡슐화를 지키지 못한다.class Point{ public double x; public double y;} 단점 1. 내부 표현을 변경하기 위해 API(public 메서드와 필드)를 수정해야 한다.좋지 않은 예시public class BadDesign { public List names; // 직접 접근 가능한 public 필드 public BadDesign() { names = new ArrayList(); } public void addName(String name) { names.add(name); } pub..
15. 클래스와 멤버의 접근 권한을 최소화하라.캡슐화잘 설계된 컴포넌트란?캡슐화가 잘 지켜진 컴포넌트이다.클래스 내부 데이터와 내부 구현 정보를 외부 컴포넌트로부터 잘 숨긴다.모든 내부 구현을 완벽히 숨겨, 구현(내부 로직)과 API(public, 외부 공개)를 깔끔하게 분리한다.오직 API를 통해서만 다른 컴포넌트와 소통하며, 서로의 내부 동작 방식에는 전혀 개의치 않는다.public class BankAccount { private double balance; // 내부 구현 // API (외부 공개) public void deposit(double amount) { if (amount > 0) { balance += amount; } ..
14. Comparable을 구현할지 고려하자.Comparablepublic interface Comparable { int compareTo(T t);}compareTo는 Object의 메서드가 아니다.compareTo는 단순 동치성 비교에 더해 순서까지 비교할 수 있으며, 제네릭하다.자연적인 순서 (논리적으로 자연스러운 순서) 를 정할 수 있다.검색, 극단값 계산, 자동 정렬되는 컬렉션 관리도 쉽게 할 수 있다.배열이라면 Arrays.sort()를 이용해 손쉽게 정렬할 수 있다.사실상 자바 플랫폼 라이브러리의 모든 값 클래스와 열거 타입이 Comparable을 구현했다.정렬된 컬렉션인 TreeSet과 TreeMap, 검색과 정렬 알고리즘을 사용하는 유틸리티 클래스인 Collections와 Arr..
clone 재정의는 주의해서 진행하라Cloneablepublic interface Cloneable { }Cloneable : 복제해도 되는 클래스임을 명시하는 용도의 믹스인 인터페이스(기능 추가)이다.구현할 메서드가 존재하지 않으며, Object.clone()의 동작 방식만을 결정한다. Object.clone()public class Object {// ... @IntrinsicCandidate protected native Object clone() throws CloneNotSupportedException;Object는 clone() 메서드를 가지고 있지만, Cloneable 인터페이스를 구현하고 있지 않다.동작 방식Cloneable을 구현하지 않은 클래스에서 clone을 호출하면..
toString을 항상 재정의하라.toString()객체를 문자열로 표현하는 메서드Object 클래스에 정의된 메서드 용도디버깅/로깅문자열 변환 시에 자동 호출객체 출력 Object의 기본 toString() 구현단순히 클래스_이름@16진수로_표시한_해시코드를 반환한다.toString의 일반 규약에 따르면 "간결하면서 사람이 읽기 쉬운 형태의 유익한 정보" 를 반환해야 한다.PhoneNumber@adbbd가 아닌 "707-867-5309" toString의 규약 : 모든 하위 클래스에서 toString을 재정의하라toString을 잘 구현한 클래스는 사용하기에 훨씬 즐겁고, 그 클래스를 사용한 시스템은 디버깅하기 쉽다.public static void main(String[] args) { Ph..
equals를 재정의하려거든 HashCode도 재정의하라.equals를 재정의한 클래스 모두에서 HashCode도 재정의해야 한다.그렇지 않으면 HashMap이나 HashSet 같은 컬렉션의 원소로 사용할 때 문제를 일으킬 것이다. HashCode란?임의의 데이터(객체, 문자열)을 고정된 길이의 정수값으로 매핑하는 함수(해시 함수)의 결과같은 내용의 객체는 동일한 해시 코드를 가진다.다른 내용의 객체라도 동일한 해시 코드를 가질 수 있다. (해시 충돌)해시 충돌을 최소화하고 고른 분포를 가지도록 설계하는 것이 좋다. 용도해시 기반 자료구조에서 검색 시에 객체의 동일성 비교를 빠르게 수행할 수 있도록 해준다.HashMap, HashSet데이터 무결성 검증에도 사용된다. 해시 함수(hash function)..