![](http://i1.daumcdn.net/thumb/C148x148/?fname=https://blog.kakaocdn.net/dn/HVFma/btqZ4Bsu75t/JoUeoB1Y6ZyB2wKg3jDKe1/img.png)
중첩 클래스란 다른 클래스 안에 정의된 클래스를 말한다. 중첩 클래스는 자신을 감싼 바깥 클래스에서만 쓰여야 하며, 그 외의 쓰임새가 있다면 톱 레벨 클래스로 만들어야 한다. 중첩 클래스의 종류 1. 정적 멤버 클래스 2. (비정적) 멤버 클래스 3. 익명 클래스 4. 지역 클래스 이 중 첫번째, 정적 멤버 클래스를 제외한 나머지를 내부 클래스(inner class)라고 한다. 정적 멤버 클래스 정적 멤버 클래스는 바깥 클래스의 private 멤버에도 접근할 수 있다는 점을 제외하고 일반 클래스와 똑같다. 정적 멤버 클래스는 보통 바깥 클래스와 함께 쓰일 때 유용한 public 도우미 클래스로 쓰인다. private 정적 멤버 클래스는 바깥 클래스가 표현하는 객체의 구성요소를 나타낼 때 사용된다. 공개된..
![](http://i1.daumcdn.net/thumb/C148x148/?fname=https://blog.kakaocdn.net/dn/bAemLl/btqZZyYxRZR/sDrZZc3pqwk4QIQhwDPLIK/img.png)
두 가지 이상의 의미를 표현할 수 있으며, 그중 현재 표현하는 의미를 태그 값으로 알려주는 클래스를 태그 달린 클래스라고 한다. 태그란? 클래스가 어떠한 타입인지에 대한 정보를 담고 있는 멤버 변수(필드)를 의미한다. 태그 달린 클래스는 많은 단점을 가지고 있다. 태그 달린 클래스의 단점 1. 쓸대없는 코드들이 많다. 태그에 대한 선언이 필요하기 때문에 열거형 타입 선언, 태그 필드, switch 문 등 쓸데없는 코드들이 많아진다. 태그에 따른 메서드의 행동이 달라져야 하기 때문에 switch 문이 많아져 가독성이 떨어진다. 2. 메모리를 많이 사용한다. 다른 행동을 위한 코드도 정의되기 때문에 메모리도 많이 사용하게 된다. 3. 불필요한 초기화가 필요하다. 필드를 final로 선언하려면 해당 태그에서 ..
![](http://i1.daumcdn.net/thumb/C148x148/?fname=https://blog.kakaocdn.net/dn/XgLjP/btqZFs46uj3/0k05X5XsqGQT3pmDU6QUw1/img.png)
클래스가 어떤 인터페이스를 구현한다는 것은 자신의 인스턴스로 무엇을 할 수 있는지를 클라이언트에게 말해주는 것이다. 인터페이스는 오직 이 용도로만 사용해야 한다. 메서드 없이 상수 필드만 가득한 상수 인터페이스를 사용하지 말자. 상수 인터페이스는 인터페이스를 잘못 사용한 안티 패턴이다. 클래스 내부에서 사용하는 상수는 외부 인터페이스가 아니라 내부 구현에 해당한다. 따라서 상수 인터페이스를 구현하는 것은 내부 구현을 외부로 노출하는 행위이다. 이는 사용자에게 혼란을 주고 클라이언트 코드가 내부 구현에 해당하는 상수에 종속적이게 될 수 있다. 만약 상수를 공개하고 싶다면 인스턴스화할 수 없는 유틸리티 클래스를 통해 공개하자. 혹은 그 클래스나 인터페이스에 강하게 연관된 상수라면 그 클래스나 인터페이스 자체..
![](http://i1.daumcdn.net/thumb/C148x148/?fname=https://blog.kakaocdn.net/dn/AQ0nq/btqZJ6mFHFE/C6O2PVFBvXdSOyqvVNhGfK/img.png)
자바 8 이전에는 기존 구현체를 깨트리지 않고 인터페이스에 메서드를 추가할 방법이 없었다. 자바 8부터 디폴트 메서드를 제공하여 메서드를 추가할 수 있도록 됐지만, 위험이 완전히 사라진 것은 아니다. 생각할 수 있는 모든 상황에서 불변식을 해치지 않는 디폴트 메서드를 작성하기란 어렵다. 자바 8부터 Collection에 새로 추가된 removeIf() 메서드는 Predicate 결과에 따라 원소를 제거하는 메서드이다. 범용적인 코드이지만, 모든 Collection의 구현체와 잘 어우러지는 것은 아니다. 아파치의 SynchronizedCollection 클래스는 지금도 활발히 관리되고 있지만 removeIf 메서드를 재정의하지 않는다. 그 이유는 만약 removeIf의 디폴트 구현을 물려받는다면 모든 메서..
![](http://i1.daumcdn.net/thumb/C148x148/?fname=https://blog.kakaocdn.net/dn/uiBSP/btqZvOzrhHl/P5BmwqGc94ERIlwHjETu70/img.png)
자바가 제공하는 다중 구현 메커니즘은 인터페이스와 추상 클래스가 있다. 자바 8부터는 인터페이스도 디폴트 메서드를 제공하게 되어 인터페이스와 추상 클래스 모두 인스턴스 메서드를 구현 형태로 제공할 수 있게 되었다. 그렇다면 이 둘의 차이점이 무엇일까? 인터페이스와 추상 클래스의 가장 큰 차이는 추상 클래스를 상속받아 구현하는 클래스는 반드시 추상 클래스의 하위 클래스가 되어야 한다는 점이다. 단일 상속만 가능한 자바에서 추상 클래스의 하위 클래스는 다른 클래스를 확장할 수 없기 때문에 새로운 타입을 정의하는데 커다란 제약을 가지게 되는 셈이다. 반면에 인터페이스는 선언한 메서드를 모두 정의하고 그 일반 규약을 잘 지킨 클래스라면 다른 어떤 클래스를 상속했든 같은 타입으로 취급된다. 인터페이스의 장점 1...
![](http://i1.daumcdn.net/thumb/C148x148/?fname=https://blog.kakaocdn.net/dn/cFGMCD/btqXZIV3byz/0wn7EB1sygIKj6GZIwVOAk/img.png)
프로그래머의 통제권 밖에 있어 언제 어떻게 변경될지 모르는 외부 클래스를 상속할 때는 주의해야 한다. 이러한 클래스를 상속하게 하려면 상속할 때의 주의점을 문서화해야 한다. 상속을 고려한 설계와 문서화 상속용 클래스는 재정의할 수 있는 메서드들을 내부적으로 어떻게 이용하는지 (자기 사용) 문서로 남겨야 한다. 클래스의 API로 공개된 메서드에서 클래스 자신의 또 다른 메서드를 호출할 수 있다. 이때 호출한 메서드가 재정의 가능한 메서드라면, 이 사실을 메서드의 API 설명에 명시해야 한다. 더 넓게 말하자면, 재정의 가능 메서드를 호출할 수 있는 모든 상황을 문서로 남겨야 한다. 이를 도와주는 용도로 @implSpec를 이용하면 javadoc이 내부 동작 방식을 설명하는 "Implementation Re..
![](http://i1.daumcdn.net/thumb/C148x148/?fname=https://blog.kakaocdn.net/dn/ENl6a/btqW4icMeV2/O6BxR8hOfIVUiTj8gcm4Sk/img.png)
상속은 코드를 재사용하는 강력한 수단이지만, 최선은 아니다. 잘못 사용하면 오류를 내기 쉽다. 1. 다른 패키지의 구체 클래스 상속의 단점 해당 장의 '상속'은 클래스가 다른 클래스를 확장하는 것을 의미한다. 다른 패키지의 구체 클래스를 상속하는 일은 위험하다. (인터페이스 확장 및 구현 제외) 메서드 호출과는 다르게 상속은 캡슐화를 깨트린다. 하위 클래스가 상위 클래스의 구현에 의존할 수 밖에 없기 때문이다. 상위 클래스의 구현은 변경될 수 있는데, 그러다보면 하위 클래스는 코드 수정 없이도 망가질 수 있다. // 상속을 잘못 사용한 예 class InstrumentedHashSet extends HashSet { // 추가된 원소의 수 private int addCount = 0; //생성자 publ..
![](http://i1.daumcdn.net/thumb/C148x148/?fname=https://blog.kakaocdn.net/dn/Nt8is/btqVV2XqDin/kG2QKFxnLdOhkX0g9uykXk/img.png)
변경 가능한 클래스로 만들 타당한 이유가 없다면, 가능한 한 변경 불가능한 불변 클래스로 만드는 것이 좋다. 불변 클래스란 객체가 생성된 시점부터 파괴되는 시점까지 그 내부 값을 수정(변경)할 수 없는 클래스를 말한다. 대표적인 예로는 String, Wrapper Class, BigInteger, BigDecimal 등이 있다. 불변 클래스는 설계, 구현, 사용이 쉬우며, 오류가 생길 여지가 적고 안전하다. 불변 클래스 생성 5가지 규칙 1. 객체 상태를 변경하는 메서드를 제공하지 않는다. (Setter) 2. 클래스를 확장할 수 없도록 한다. 하위 클래스에 의해 객체의 상태를 변하게 하는 사태를 막아준다. 3. 모든 필드를 final로 선언한다. 설계자의 의도를 명확히 드러내는 방법이다. 4. 모든 필..
![](http://i1.daumcdn.net/thumb/C148x148/?fname=https://blog.kakaocdn.net/dn/zKAcv/btqVSu0KGxf/ntPScHMmSOkkkkes9gnmyk/img.png)
단순히 인스턴스 필드를 모아놓는 클래스는 public이면 안된다. 데이터 필드에 직접 접근이 가능해져 캡슐화의 이점을 제공하지 못하기 때문이다. // public이면 안된다!! class Point { public double x; public double y; } 위와 같은 클래스는 API를 수정하지 않고는 내부 표현을 바꿀 수 없고, 불변식을 보장할 수 없으며, 외부에서 필드에 접근할 때 부수 작업을 수행할 수도 없다. public 클래스의 가변 필드는 절대 노출하면 안 된다! 캡슐화의 이점을 제공하지 못함 API 수정 없이 내부 표현을 변경하지 못한다. 불변식을 보장할 수 없다. 외부에서 필드에 접근할 때 부수 작업을 수행할 수 없다. 이런 클래스는 접근자와 변경자 메서드를 활용해 데이터를 캡슐화할..