톱레벨 클래스가 소스 파일 하나에 들어있으면 심각한 위험을 감수해야한다. //A.java 파일 class A { static final String NAME = "ab"; } class B{ static final String NAME = "cd"; } //B.java 파일 class A { static final String NAME = "ef"; } class B{ static final String NAME = "gh"; } 만약 다른곳에서 A 클래스와 B 클래스를 참조할때 중복 정의이기 때문에 이와 같이 작성하면 안된다. 컴파일러에 어느 소스 파일을 먼저 건네느냐에 따라 동작이 달라지므로 이렇게 사용하면 안된다. 해결방안은 단순히 톱레벨 클래스들을 서로 다른 소스파일로 분리하는 것이다. 굳이 한 ..
중첩 클래스 (nested class) 중첩 클래스는 다른 클래스 안에 정의된 클래스를 말한다. 자신을 감싼 바깥 클래스에서만 쓰여야함 정적 멤버 클래스, (비정적) 멤버 클래스, 익명 클래스, 지역 클래스 정적 멤버 클래스 다른 클래스 내부에서 static으로 선언된 클래스 다른 정적 멤버와 똑같은 규칙 적용 흔히 바깥 클래스와 함께 쓰일때만 유용한 public 도우미 클래스로 사용 public class Calculator { public enum Operation { // 열거 타입도 암시적 static 이다. PLUS, MINUS, MULTIPLE, SUBTRACT } } 비정적 멤버 클래스 다른 클래스 내부에서 static 없이 선언된 클래스 비정적 멤버 클래스 인스턴스는 바깥 클래스 인스턴스와..
태그 달린 클래스 두 가지 이상의 의미를 표현할 수 있고 현재 표현하는 의미를 태그 값으로 알려주는 클래스 public class Figure { enum Shape {RECTANGLE, CIRCLE} // 태그 private final Shape shape; // 이 필드들은 사각형일때만 사용 private final double length; private final double width; // 이 필드는 원형일때만 사용 private final double radius; //원용 생성자 public Figure(Shape shape, double radius) { this.shape = shape; this.length = 0; this.width = 0; this.radius = radius; ..
인터페이스는 자신을 구현한 클래스의 인스턴스를 참조할 수 있는 타입 역할을 하는데, 인터페이스는 이 용도로만 사용해야 한다. 상수 인터페이스는 메서드 없이 static final 필드로만 가득찬 인터페이스로, 인터페이스를 잘못 사용한 예이다. //상수 인터페이스 안티패턴 - 사용금지 public interface PhysicalConstants { static final double AVOGADROS_NUMBER = 6.022_140_857e23; static final double BOLTZMANN_CONSTANT = 1.380_648_52e-23; static final double ELECTRON_MASS = 9.109_383_56e-31; } 클래스 내부의 상수는 외부 인터페이스가 아니라 내부 구..
디폴트 메서드의 도입 - 자바8부터는 기존 인터페이스에 메서드를 추가할 수 있도록 디폴트 메서드를 도입. but 디폴트 메서드를 재정의하지 않은 모든 클래스에서 디폴트 구현이 쓰이게 되므로 모든 기존 구현체들과 매끄럽게 연동되리라는 보장을 할 수 없음 - 자바8에서는 핵심 컬렉션 인터페이스들에 다수의 디폴트 메서드가 추가됨 → 람다 활용 위해 추가된 메서드들은 품질이 높고 범용적이어서 대부분 상황에서 잘 작동 but 모든 상황에서 불변식을 해치지 않는 디폴트 메서드를 작성하긴 어렵다. default boolean removeIf(Predicate
자바가 제공하는 다중 구현 메커니즘 : 인터페이스, 추상 클래스 추상 클래스가 정의한 타입을 구현하는 클래스는 반드시 추상클래스의 하위 클래스가 되어야 한다. 자바는 단일 상속을 지원하기 때문에 추상 클래스 방식은 새로운 타입을 정의하는데 제약 but 인터페이스를 구현한 클래스는 다른 어떤 클래스를 상속했든 간에 같은 타입으로 취급 인터페이스 기존 클래스에도 손쉽게 새로운 인터페이스를 구현해넣을 수 있다.but 추상 클래스는 그렇지 않다. 새로 추가된 추상 클래스의 모든 자손이 상속구조를 가지게 되며 혼란을 줌. 인터페이스가 요구하는 메서드를 추가하고 implements 구문만 추가하면 된다. 인터페이스는 믹스인에 적절함 : 원래의 주된 타입 외에 특정 선택적 행위를 제공 효과 but 추상 클래스는 그렇..
상속을 고려한 설계와 문서화 1) 메서드를 재정의할때 어떤일이 일어나는지 정확히 정리하여 문서로 남겨라. 상속용 클래스는 재정의할 수 있는 메서드(public, protected 이면서 final이 아닌 메서드)들을 내부적으로 어떻게 이용하는지 문서로 남겨야 한다. 2) 효율적인 하위 클래스를 어려움 없이 만들 수 있게 하기 위해 클래스의 내부 동작 과정 중간에 끼어들 수 있는 훅을 잘 선별하여 protected 메서드 형태로 공개해야 할 수도 있다. 3) 상속용으로 설계한 클래스를 시험하는 방법은 직접 하위 클래스를 만들어보는 것이다. 꼭 필요한 protected 멤버를 놓쳤다면 빈 자리가 드러남, 전혀 쓰이지 않는 protected 멤버는 사실 private 임 등을 알 수 있다. 배포전에 반드시 하..
상속은 코드를 재사용하는 강력한 수단이나 항상 최선은 아니다. 다른 패키지의 구체 클래스를 상속하는 일은 위험하다. 캡슐화를 깨뜨리는 상속 상위 클래스가 어떻게 구현되느냐에 따라 하위 클래스의 동작에 이상이 생길 수 있음 설계자가 확장을 충분히 고려하지 않으면, 하위 클래스는 상위 클래스 변화에 맞춰 수정되어야만 한다. public class InstrumentedHashSet extends HashSet { private int addCount = 0; public InstrumentedHashSet(int initCap, float loadFactor) { super(initCap, loadFactor); } @Override public boolean add(E e) { addCount++; ret..