반응형

스터디 50

[Effective Java] Item20. 추상 클래스보다는 인터페이스

추상클래스와 인터페이스 자바는 추상 클래스와 인터페이스로 다중 구현 메커니즘을 제공합니다. 자바 8부터 인터페이스도 디폴트 메서드를 제공할 수 있게 되어 두 메커니즘 모두 인스턴스 메서드를 구현 형태로 제공할 수 있습니다. 인터페이스를 우선적으로 고려해야 하는 이유 추상 클래스는 구현한 클래스는 반드시 하위클래스여야 합니다. 자바는 단일 상속만 지원하기 때문에 추가적으로 새로운 타입을 정의하는데 제약이 있습니다. Comparable 인터페이스는 jdk1.2버전에서 추가되었습니다. 반면 이를 구현하나 String클래스와 Integer클래스는 jdk1.0버전에서부터 있었습니다. 만약 Comparable을 추상 클래스 방식으로 지원한다면 String과 Integer의 공통 조상이어야 합니다. 이 외에도 Com..

[Effective Java] Item19. 상속을 고려해 설계하고 문서화하라

메서드를 재정의하면 어떤 일이 일어나는지를 정확히 정리하여 문서로 남겨야 합니다. 달리 말하면 재정의 할 수 있는 메서드들을 내부적으로 어떻게 이용하는지 문서로 남겨야 합니다. API문서의 메서드 설명 끝에 "Implementation Requirements"로 시작하는 절이 바로 내부 동작을 설명하는 곳입니다. 이는 메서드 주석에 @implSpec 태그를 붙여주면 자바독 도구가 생성해줍니다. @implSpec 태그는 자바8에 처음 도입되었습니다. 이 태그를 활성화하려면 명령줄 매개변수로 -tag "implSpec:a:Implementationo Requirements:"를 지정해주면 됩니다. 문서화 말고도 고려해야 할 것들이 더 있습니다. 클래스의 내부 동작 과정 중간에 끼어들 수 있는 훅(hook)을..

[Effective Java] Item18. 상속보다는 컴포지션

여기서 말하는 상속은 다른 클래스를 확장하는 구현 상속입니다. 상속의 문제점 메서드 호출과 달리 상속은 캡슐화를 깨뜨립니다. 상위 클래스는 내부 구현이 달라질 수 있으며, 이로 인해 하위 클래스의 동작에 이상이 생길 수 있습니다. 또한, 자기사용(self-use) 여부에 따라 상속한 클래스에서 원하는 결과를 얻지 못 할 수도 있습니다. 또한 자기사용 여부는 다음 버전에서 유지될지 알 수 없습니다. public class BadHashSet extends HashSet { //추가 된 원소 수 private int addCount = 0; @Override public boolean add(E e) { addCount++; return super.add(e); } @Override public boolea..

[Effective Java] Item17. 변경 가능성을 최소화

불변 클래스의 정의 인스턴스의 내부 값을 수정할 수 없는 클래스로 객체가 파괴되는 순간까지 절대 달라지지 않습니다. 대표적으로 String 클래스가 해당합니다. 불변 클래스의 장점 가변 클래스보다 설계, 구현, 사용이 쉽습니다. 가변 클래스보다 오류 발생 가능성이 적고 안전합니다. 기본적으로 Tread-safe하므로 안심하고 공유할 수 있어서 재사용을 할 수 있습니다. 방어적 복사를 할 필요가 없습니다. 따라서 clone메서드나 복사 생성자를 제공하지 않는 것이 좋습니다. 불변 객체는 그 자체로 실패 원자성(메서드에서 예외가 발생해도 그 객체는 메서드 호출전과 똑같은 유요한 상태여야 함)을 제공합니다. 불변 객체끼리는 내부 데이터를 공유할 수 있습니다. public class BigInteger { fi..

[Effective Java] Item16. public클래스에서는 접근자 메서드 사용

public 클래스는 모든 필드를 private으로 하고 접근자를 제공하는 것이 좋습니다. public class Member { private String name; private int age; public String getName() { return name; } public int getAge() { return age; } } 자바 플랫폼 라이브러리에는 이 규칙을 어기는 사례가 있습니다. 불변 필드라도 완전히 안전할 수 없으므로 public 클래스는 무조건 필드를 직접 노출하지 않는 것이 좋습니다. 하지만 default 클래스 혹은 private 중첩 클래스라면 필드를 노출해도 문제는 없습니다. 오히려 노출하는 편이 나을 때도 있습니다.(깔끔)

[Effective Java] Item15. 클래스와 멤버의 접근 권한을 최소화

캡슐화의 장점 개발속도 향상: 여러 컴포넌트를 병렬로 개발할 수 있기 때문 시스템 관리비용 감소: 빠른 파악 및 적은 교체 부담 성능 최적화에 도움: 캡슐화 자체가 성능을 높여주지는 않지만, 다른 컴포넌트에 영향을 주지 않고 특정 컴포넌트만 최적화 가능 재사용성 향상: 외부에 거의 의존하지 않고 독자적으로 동작한다면 다른 환경에서도 유용하게 쓰일 가능성이 높음 큰 시스템 제작 난이도 감소: 시스템이 완성되지 않은 상태에도 개별 컴포넌트의 동작을 검증할 수 있음 접근 제어 메커니즘 정보 은닉(캡슐화)를 위한 다양한 장치 중 하나. 접근 제어자(private, default(package-private), protected, public)로 각 요소의 접근성을 결정 접근 제어자 적용 가능 대상 같은 클래스 ..

[Effective Java] Item14. Comparable을 구현할지 고려

Comparable와 compareTo Comparable는 compareTo 메서드를 하나만 갖고있는 있는 인터페이스입니다. compareTo 메서드는 두 가지 성격만 빼면 eqauls와 같습니다. compareTo는 동치성 비교 뿐아니라 순서까지 비교할 수 있으며 제네릭합니다. compareTo의 일반 규약 두 객체 참조의 순서를 바꿔도 같은 결과가 나와야 합니다. a pn.lineNum); } 해시코드 값의 차를 기준으로하는 경우 - 추이성을 위배! 이 방식은 사용하면 안됩니다. 정수 오버플로우를 일으키거나 IEEE 754 부동소수점 계산 방식에 따른 오류를 낼 수 있습니다. static Comparator hashCodeOrder = new Comparator() { public int compa..

[Effective Java] Item13. clone 재정의는 주의해서 진행

복제 기능은 (변환)생성자와 (변환)팩토리를 이용하는게 최고입니다. (배열은 예외적으로 clone 메서드를 사용하는 것이 좋습니다.) Cloneable 복제해도 되는 클래스임을 명시하는 용도의 믹스인 인터페이스(mixin interface)입니다. 하지만 clone 메서드가 선언된 곳이 Cloneable이 아닌 Object이고 이마저도 protected입니다. 따라서 Cloneable을 구현하는 것만으로는 외부 객체에서 clone 메서드를 호출할 수 없습니다.(리플렉션을 사용하면 가능하지만, 해당 객체가 접근 허용된 clone메서드를 제공한다는 보장이 없기 때문에 100%성공하지도 않습니다.) Cloneable 인터페이스는 Object의 clone 메서드의 동작 방식을 결정합니다. Clonable을 구현..

[Effective Java] Item12. toString을 항상 재정의

toString을 재정의하지 않으면 클래스이름@16진수의해시코드를 반환합니다. 따라서 toString의 일반 규약에 따라서 사람이 읽기 쉬운 형태의 유익한 정보를 반환해야합니다. toString메서드는 println, printf, 문자열 연결(+), assert 구문에 넘길때, 디버거가 객체를 출력할 때 자동으로 호출됩니다. 따라서 직접 호출하지 않더라도 무조건 재정의해야 합니다. toString메서드는 객체의 주요 정보를 모두 반환하는 것이 좋습니다. 하지만 객체가 거대하거나 객체의 상태가 문자열로 표현하기 적합하지 않는 경우 요약정보라도 담는 것이 좋습니다. toString메서드는 필요할 경우 포맷을 문서화해야 합니다. 특히 전화번호나 행렬 같은 값 클래스인 경우 권장사항입니다. 단, 포맷을 한번 ..

[Effective Java] Item11. equals재정의시 무조건 hashCode도 재정의

equals 재정의시 hashCode를 재정의하지 않으면 해당 클래스의 인스턴스를 HashMap, HashSet과 같은 컬렉션의 원소로 사용할 때 문제가 발생합니다. 논리적으로 같은 객체는 같은 해시코드를 반환해야합니다. hashCode 재정의 방법 public class Address { private int zipcode; private String city; private List street; //전형적인 hashCode메서드 @Override public int hashCode() { int result = zipcode; //zipcode 대신 Integer.hashCode(zipcode) 사용 가능 result = 31 * result + (city != null ? city.hashCode..