Effective Java 3E
학습기록 - 멤버 클래스는 되도록 static으로 만들라
중첩 클래스(nested class)란 다른 클래스 안에 정의된 클래스를 말한다. 중첩 클래스는 자신을 감싼 바깥 클래스에서만 쓰여야 하며, 그 외의 쓰임새가 있다면 톱레벨 클래스로 만들어야 한다. 중첩 클래스의 종류는 정적 멤버 클래스, (비정적) 멤버 클래스, 익명 클래스, 지역 클래스, 이렇게 네 가지다. 이 중 첫 번째를 제외한 나머지는 내부 클래스(inner class)에 해당한다. 이번에는 각각의 중첩 클래스를 언제 그리고 왜 사용해야 하는지 이야기한다. 먼저 가장 간단한 정적 멤버 클래스를 알아보자. 정적 멤버 클래스는 다른 클래스 안에 선언되고, 바깥 클래스의 private 멤버에도 접근할 수 있다는 점만 제외하고는 일반 클래스와 똑같다. 정적 멤버 클래스는 다른 정적 멤버와 똑같은 접근 ..
학습기록 - 태그 달린 클래스보다는 클래스 계층 구조를 활용하라
두 가지 이상의 의미를 표현할 수 있으며, 그중 현재 표현하는 의미를 태그 값으로 알려주는 클래스를 본 적이 있을 것이다. 다음 코드는 원과 사각형을 표현할 수 있는 클래스다. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 Class Figure{ enum Shape { RECTANGLE, CIRCLE }; final Shape shape; double length; double width; double radius; Figure(double radius){ shape = Shape.CIRCLE; this.radius = radius; } Figure(double length, double wid..
학습기록 - 인터페이스는 타입을 정의하는 용도로만 사용하라
인터페이스는 자신을 구현한 클래스의 인스턴스를 참조할 수 있는 타입 역할을 한다. 달리 말해, 클래스가 어떤 인터페이스를 구현한다는 것은 자신의 인스턴스로 무엇을 할 수 있는지를 클라이언트에 얘기해주는 것이다. 인터페이스는 오직 이 용도로만 사용해야 한다. 이 지침에 맞지 않는 예로 소위 상수 인터페이스라는 것이 있다. 상수 인터페이스란 메서드 없이, 상수를 뜻하는 static final 필드로만 가득 찬 인터페이스를 말한다. 그리고 이 상수들을 사용하려는 클래스에서는 정규화된 이름(qualified name)을 쓰는 걸 피하고자 그 인터페이스를 구현하곤 한다. 아래의 예를 보자. 1 2 3 4 5 public interface PhysicalConstants{ static final double AVO..
학습기록 - 인터페이스는 구현하는 쪽을 생각해 설계하라
자바 8 전에는 기존 구현체를 깨뜨리지 않고는 인터페이스에 메서드를 추가할 방법이 없었다. 인터페이스에 메서드를 추가하면 보통은 컴파일 오류가 나는데, 추가된 메서드가 우연히 기존 구현체에 이미 존재할 가능성은 아주 낮기 때문이다. 자바 8에 와서 기존 인터페이스 메서드를 추가할 수 있도록 디폴트 메서드를 소개했지만, 위험이 완전히 사라진 것은 아니다. 디폴트 메서드를 선언하면, 그 인터페이스를 구현한 후, 그 인터페이스를 구현한 후 디폴트 메서드를 재정의하지 않은 모든 클래스에서 디폴트 구현이 쓰이게 된다. 이처럼 자바에도 기존 인터페이스에 메서드를 추가하는 길이 열렸지만 모든 기존 구현체들과 매끄럽게 연동되리라는 보장은 없다. 자바 7까지의 세상에서는 모든 클래스가 "현재의 인터페이스에 새로운 메서드..
학습기록 - 추상 클래스보다는 인터페이스를 우선하라
자바가 제공하는 다중 구현 메커니즘은 인터페이스와 추상 클래스, 이렇게 두 가지다. 자바 8부터 인터페이스도 디폴트 메서드(default method)를 제공할 수 있게 되어, 이제는 두 메커니즘 모두 인스턴스 메서드를 구현 형태로 제공할 수 있다. 한편, 둘의 가장 큰 차이는 추상 클래스가 정의한 타입을 구현하는 클래스는 반드시 추상 클래스의 하위 클래스가 되어야 한다는 점이다. 자바는 단일 상속만 지원하니, 추상 클래스 방식은 새로운 타입을 정의하는 데 커다란 제약을 안게 되는 셈이다. 반면 인터페이스가 선언한 메서드를 모두 정의하고 그 일반 규약을 잘 지킨 클래스라면 다른 어떤 클래스를 상속했든 같은 타입으로 취급된다. 기존 클래스에도 손쉽게 새로운 인터페이스를 구현해 넣을 수 있다. 인터페이스가 ..
학습기록 - 상속을 고려해 설계하고 문서화하라. 그러지 않았다면 상속을 금지하라
상속을 고려한 설계와 문서화란 정확히 무엇일까? 우선, 메서드를 재정의하면 어떤 일이 일어나는지 정확히 정리하여 문서로 남겨야 한다. 달리 말하면, 상속용 클래스는 재정의할 수 있는 메서드들을 내부적으로 어떻게 이용하는지(자기사용) 문서로 남겨야 한다. 클래스의 API로 공개된 메서드에서 클래스 자신의 또 다른 메서드를 호출할 수도 있다. 그런데 마침 호출되는 메서드가 재정의 가능 메서드라면 그 사실을 호출하는 메서드의 API 설명에 적시해야 한다. 덧붙여서 어떤 순서로 호출하는지, 각각의 호출 결과가 이어지는 처리에 어떤 영향을 주는지도 담아야한다('재정의 가능' 이란 public과 protected 메서드 중 final이 아닌 모든 메서드를 뜻한다). 더 넓게 말하면, 재정의 가능 메서드를 호출할 수..