한 소스 파일에 톱 레벨 클래스를 여러개 선언하면 컴파일 순서에 따라 결과가 달라질 수 있다. 다른 클래스에 딸린 부차적인 클래스는 정적 멤버 클래스로 만드는 것이 낫다. 가독성이 좋으며 private로 선언해서 접근 범위도 최소한으로 관리할 수 있다. 소스파일 하나에 톱레벨 클래스를 여러개 선언하더라도 자바 컴파일러에서 오류를 뱉진 않지만 아무런 득이 없을 뿐더러 심각한 위험을 감수해야 하는 행위이다. 이렇게 하면 한 클래스를 여러 가지로 정의할 수 있으며, 컴파일 시 각각의 .class파일로 분리가 되지만 그 중 어느것을 사용할지는 어느 소스 파일을 먼저 컴파일 하는가에 따라 달라지기 때문이다. 파일명은 Utensil.java 이지만 컴파일시 Utensil.class 파일과 Dessert.class ..
중첩클래스 : 클래스에 필드와 메서드 처럼 클래스 내부에 정의된 클래스. 중첩 클래스는 자신을 감싼 바깥 클래스에서만 쓰여야 하며, 그 외의 쓰임새가 있다면 톱레벨 클래스로 만들어야 한다. 중첩 클래스의 종류는 정적 멤버 클래스, 비정적 멤버 클래스, 익명 클래스, 지역 클래스로 네 가지다. 정적 멤버 클래스를 제외한 3가지는 내부 클래스(inner class)에 해당한다. 멤버 클래스란 클래스의 구성요소가 되는 중첩클래스로 메서드 내부에 선언된 클래스는 멤버 클래스가 아니다. 지역변수 전역변수 중 전역변수는 클래스 내부 전체에서 쓰이는 멤버 변수인 것처럼 익명 클래스와 지역 클래스는 scope가 전역이 아닌, 사용하는 곳에 한정되고 클래스의 전역에서 사용할 수 있는 것은 정적 멤버 클래스와 비정적 멤버..
태그 달린 클래스의 단점 쓸데없는 코드가 많다. 가독성이 나쁘다. 메모리도 많이 사용한다. 필드를 final로 선언하려면 불필요한 필드까지 초기화해야 한다. 인스턴스 타입만으로는 현재 나타내는 의미를 알 길이 없다. 클래스 계층 구조로 바꾸면 모든 단점을 해결할 수 있다. 태그달린 클래스란? 클래스가 가지고 있는 필드 중 일부가 클래스의 구체적인 타입을 나타내는 경우. 클래스가 어떤 타입인지 정보를 담고 있는 필드를 의미한다. 태그 달린 클래스에는 단점이 한가득이다. 우선 열거 타입 선언, 태그 필드, switch 문 등 쓸데 없는 코드가 많다. (RECTANGLE 입장에서는 radius가 불필요하고 CIRCLE 입장에서는 length와 width가 필요하지 않다.) 여러 구현이 한 클래스에 혼합돼 있어..
상수를 정의하는 용도로 인터페이스를 사용하지 말 것! 클래스 내부에서 사용할 상수는 내부 구현에 해당한다. 내부 구현을 클래스의 API로 노출하는 행위가 된다. 클라이언트에 혼란을 준다. 상수를 정의하는 방법 특정 클래스나 인터페이스 열거형 인스턴스화 할 수 없는 유틸리티 클래스 네임 스페이스 없이 편리하게 필드값을 사용하고자 인터페이스에 상수를 정의한다면 안티 패턴으로 권장하지 않는 코드이다. 인터페이스의 원래 용도를 오염시키기 때문. 인터페이스를 만드는 의도는 타입을 정의하기 위해서이다. 인터페이스는 공통 사용기술서이자 타입정의서이지 실질적으로 상수를 사용하는 곳은 class 에서 사용하니 class 내부에 정의하는 것이 맞다. 만약 여러군데에서 사용하는 상수라면 상속할 수 없는 유틸리티 클래스에 정..
인터페이스에 디폴트 메서드 기능이 생기면서 인터페이스를 구현하면 공통적인 기능을 사용할 수 있고 반드시 오버라이딩 하지 않아도 되는 메서드여서 추상 클래스보다 가볍게 사용할 수 있지만 그렇다고 모든 위험에서 해방된 것은 아니다. 기존 사용되고 있는 인터페이스에 디폴트 메서드 구현을 추가하는 것은 위험한 일이다. 디폴트 메서드는 구현 클래스에 대해 아무것도 모른 채 합의 없이 무작정 "삽입"될 뿐이다. 디폴트 메서드는 기존 구현체에 런타임 오류를 일으킬 수 있다. 인터페이스를 설계할 때는 세심한 주의를 기울여야 한다. 서로 다른 방식으로 최소한 세 가지는 구현해보자. 이미 다른곳에서 많이 사용되고 있는 인터페이스에 디폴트 메서드를 추가한다면 해당 클래스를 구현한 모든 클래스에게 해당 기능이 무조건 추가가 ..
인터페이스의 장점 자바 8 부터 인터페이스도 디폴트 메서드를 제공할 수 있다. 기존 클래스도 손쉽게 새로운 인터페이스를 구현해 넣을 수 있다. 인터페이스는 믹스인(mixin) 정의에 안성맞춤이다. 계층구조가 없는 타입 프레임워크를 만들 수 있다. 래퍼 클래스와 함께 사용하면 인터페이스는 기능을 향상시키는 안전하고 강력한 수단이 된다. 구현이 명백한 것은 인터페이스의 디폴트 메서드를 사용해 프로그래머의 일감을 덜어줄 수 있다. 인터페이스는 보통 타입을 정의할 때 사용하고 추상(abstract) 클래스는 인터페이스의 구현체를 일부 기본적으로 제공할 때 사용한다. 현재 챕터에서는 추상클래스를 상속하여 기능을 제공하기 보다는 인터페이스를 우선적으로 사용하는 것이 장점이 많다는 이야기이다. 추상클래스를 상속받으려..
상속용 클래스는 내부 구현을 문서로 남겨야 한다. @implSpac을 사용할 수 있다. 내부 동작 중간에 끼어들 수 있는 훅(hook)을 잘 선별하여 protected 메서드로 공개해야 한다. 상속용으로 설계한 클래스는 배포 전에 반드시 하위 클래스를 만들어 검증해야한다. 상속용 클래스의 생성자는 재정의 가능한 메서드를 호출해서는 안된다. Cloneable과 Serializable을 구현할 때 조심해야 한다. 상속용으로 설계한 클래스가 아니라면 상속을 금지한다. final 클래스 또는 private 생성자 상속을 고려한 설계와 문서화는 메서드를 재정의하면 어떤 일이 일어나는지를 정확히 정리하여 문서로 남겨야한다. 상속용 클래스는 재정의할 수 있는 메서드들을 내부적으로 어떻게 사용하는지 문서로 남겨야 한다..
상속은 코드를 재사용하는 강력한 수단이지만 항상 최선은아니다. 잘못 사용하면 오류를 내기 쉬운 소프트웨어를 만들게 된다. 상위 클래스와 하위 클래스를 모두 같은 프로그래머가 통제하는 패키지 안에서라면 상속도 안전한 방법이다. 확장할 목적으로 설계되었고 문서화도 잘 된 클래스도 마찬가지로 안전하다. 하지만 일반적인 구체 클래스를 패키지 경계를 넘어 다른 패키지의 구체 클래스를 상속하는 일은 위험하다. 메서드 호출과 달리 상속은 캡슐화를 깨뜨린다. 다르게 말하면 상위 클래스가 어떻게 구현되느냐에 따라 하위 클래스의 동작에 이상이 생길 수 있다. 그 여파로 코드 한 줄 건드리지 않은 하위 클래스가 오작동할 수 있다. 이러한 이유로 상위 클래스 설계자가 확장을 충분히 고려하고 문서화도 제대로 해두지 않으면 하위..