생성자를 이용한 인스턴스 생성 클라이언트가 클래스의 인스턴스를 얻는 대표적인 방법으로 public 생성자를 이용한 방법이 있다. [public 생성자를 이용한 인스턴스 생성 방법] 정적 팩터리 메서드를 이용한 인스턴스 생성 이 외에도 인스턴스를 얻는 방법이 있는데 바로 정적 팩터리 메서드를 사용하는 것이다. [정적 팩터리 메소드를 이용한 인스턴스 생...
생성자와 매개변수의 제약 > 정적 팩터리 메서드와 생성자는 선택적 매개변수가 많을 때 적절히 대응하기 어렵다는 공통점이 있다. 이런 제약이 있을 때 유용한 방법이 [점층적 생성자 패턴]이다. 점층적 생성자 패턴 필수 매개변수 1개와 선택 매개변수를 1개 받는 생성자, 필수 매개변수 1개와 선택 매개변수를 2개까지 받는 생성자... 이런 방식으로 선택 매개...
싱글턴(SingleTon) > 싱글턴 이란 인스턴스를 오직 하나만 생성할 수 있는 클래스를 말한다. [싱글턴 구현] 싱글턴을 사용하는 경우 > 싱글턴의 전형적인 예로는 함수와 같은 무상태 객체나 설계상 유일해야하는 시스템 컴포넌트를 들 수 있다. 그런데 클래스를 싱글턴으로 만들면 이를 사용하는 클라이언트를 테스트하기가 어려워 진다. 타입을 인터페이스로...
인스턴스화를 하지 않는 유틸리티클래스 > 정적(static) 메서드와 정적(static) 필드만을 담은 클래스는 객체지향과는 거리가 있지만 쓰임새가 있다. 와 처럼 기본 타입 값이나 배열 관련 메서드들을 모아놓는다. 처럼 특정 인터페이스를 구현하는 객체를 생성해주는 정적 메서드(혹은 팩토리)를 모아놓을 수도 있다. 클래스와 관련한 메서드들을 모아놓을 때...
자원에 의존하는 클래스 > 사용하는 자원에 따라 동작이 달라지는 클래스에는 정적 유틸리티 클래스나 싱글턴 방식이 적합하지 않다. 많은 클래스가 하나 이상의 자원에 의존한다. 이런 클래스는 종종 정적 유틸리티 클래스로 구현된다. [정적 유틸리티를 잘못 사용한 경우] 위의 코드는 유연하지 않고 테스트하기가 어렵다. 비슷하게, 싱글턴으로 구현하는 경우도 많...
객체를 반복해서 생성하지 말고 재사용하자. > 똑같은 기능의 객체를 매번 생성하기보다는 객체 하나를 재사용하는 편이 낫다. 특히 불변 객체는 언제든지 재사용할 수 있다. [잘못된 객체 생성] 위 코드는 실행될 때마다 인스턴스를 새로 만든다. 생성자에 넘겨진 자체가 이 생성자로 만들어내려는 과 기능적으로 완전히 같기 때문이다. 명시적으로 키워드를 ...
메모리 누수를 주의해야 한다. 자바에서는 가비지 컬렉터가 다쓴 객체를 알아서 회수해간다 하지만 그렇다고해서 메모리 관리에 신경쓰지 않으면 안된다. 메모리 누수가 발생하는 프로그램을 오래 실행하다보면 점차 가비지 컬렉션 활동과 메모리 사용량이 늘어나 결국 성능이 저하되거나 메모리초과() 오류가 발생할 수 있다. [메모리 누수가 일어나는 스택 구현] 위 코...
자바가 제공하는 객체 소멸자 - finalizer와 cleaner * 메서드는 최상위 클래스에 포함된 메서드이다. 그래서 어느 클래스던지 메서드를 재정의 할 수 있다. 메서드를 재정의(Overriding)하면 해당 객체가 대상이 되었을 때 메서드가 호출된다. 단, 즉시 호출을 보장받을 수는 없다. 즉시 호출이 보장되지 않기 때문에 한정적 ...
리소스(자원)관리 자바 라이브러리에는 , , 등과 같이 정리() 가능한 리소스가 많은데 그런 리소스를 사용하는 클라이언트코드가 리소스 정리를 잘 안하거나 잘못하는 경우가 있다. 이런 리소스정리는 클라이언트가 놓치기 쉬워 성능문제로 이어지곤한다. 대다수의 이런 리소스들이 안전망으로 finalize 를 활용하고 있지만 그리 좋은 방법이라고 할 수는 없다. ...
equals를 재정의해야할까? 클래스의 인스턴스를 그냥 두면 오직 자기 자신과만 같게 된다. 그러니 아래와 같은 상황 중 하나에 해당된다면 재정의하지 않는것이 좋다. 값을 표현하는것이 아니라 개체를 표현하는 클래스 의 경우 의 로도 충분하다. 인스턴스의 논리적 동치성을 검사할 일이 없다. 논리적 동치성이 필요하지 않다면 의 기본 로도 충분하...
hashCode를 재정의해야하는 이유 를 재정의하지 않으면 일반규약을 어기게 되어 값을 사용하는 (, )을 사용할 때 문제가 발생할 수 있다. [를 재정의하지 않아 예상과 다르게 작동하는 ] 중복을 허용하지 않는 이 예상과 다르게 개의 크기를 갖는다는 결과가 나오는데 이는 값을 사용하는 객체가 논리적으로 같은지 비교하는 과정을 살펴보면 그 원인을 알...
toString을 항상 재정의하라 의 기본 메서드는 단순히 를 반환할 뿐이다. (의 일반 규약에 따르면 메서드는 "간결하면서 사람이 읽기 쉬운 형태의 유익한 정보" 를 반환해야 한다.) 결정적으로 규약은 "모든 하위 클래스에서 이 메서드를 재정의하라"고 한다. (을 잘 구현한 클래스는 사용하기 편하고 그 시스템은 디버깅하기가 쉬워진다.) toStrin...
clone 메서드 정의 > clone 메서드는 객체의 모든 필드를 복사하여 새로운 객체에 넣어 반환하는 동작을 수행한다. 즉, 필드의 값이 같은 객체를 새로 만드는 것이다. [객체를 복제하여 필드값 비교 예시] 으로 객체를 복제하는 경우 원본 객체와 복제된 객체가 같은 객체를 공유하므로 둘 중 하나만 변경되어도 두 객체가 모두 바뀐다. 이는 완전한 복제...
Comparable 인터페이스란? 인터페이스는 객체를 정렬하는데 사용되는 메서드인 를 정의하고 있다. 인터페이스를 구현한 클래스는 반드시 를 정의해야 한다. Comparable 인터페이스 특징 자바에서 같은 타입의 인스턴스를 비교해야만 하는 클래스들은 모두 인터페이스를 구현하고 있다. 타입을 제외한 래퍼 클래스와 알파벳, 연대같이 순서가 명확한 클래스들...
정보은닉(캡슐화) > 잘 설계된 컴포넌트는 내부 데이터와 내부 구현 정보를 외부 컴포넌트로부터 잘 숨겨 구현과 API를 분리한다. 오직 API를 통해 다른 컴포넌트와 소통하며 서로의 내부 동작 방식에는 관여하지 않는다. 이것을 정보은닉, 혹은 캡슐화라고 한다. 정보은닉 장점 시스템 개발 속도를 높인다. 여러 컴포넌트를 병렬 개발 시스템 관리 비용을 ...
접근자 메서드를 활용한 데이터 캡슐화 클래스 작성 실수: 인스턴스 필드만을 모아놓은 퇴보한 클래스 > 인스턴스 필드만을 모아놓은 클래스는 데이터에 직접 접근할 수 있으나 캡슐화의 이점을 제공하지 못한다. [인스턴스 필드만을 모아놓은 클래스] API를 수정하지 않고는 내부 표현을 바꿀 수 없다. getter / setter 가 존재해야 내부 표현 변...
불변 클래스 > 인스턴스 내부 값을 수정할 수 없는 클래스를 말한다. 불변 인스턴스에 간직된 정보는 고정되어 객체가 파괴되는 순간까지 달라지지 않는다. 가변 클래스보다 설계하고 구현하고 사용하기 쉬우며 오류가 생길 여지가 적다. 자바 라이브러리에는 , 기본 타입 박싱 클래스, , 등 다양한 불변 클래스가 존재한다. 불변 클래스의 장점 가변 클래스를 이...
상속의 위험성 상위 클래스와 하위 클래스가 모두 같은 프로그래머가 통제하는 패키지 안에서라면 상속도 안전한 방법이다. 확장할 목적으로 설계되거나 문서화도 잘 된 클래스도 마찬가지로 안전하다. 하지만, 다른 패키지의 구체 클래스를 상속하는 일은 위험성을 가지고 있다. (지금 말하는 상속은 클래스가 다른 클래스를 확장하는 구현 상속을 말한다. 클래스가 인터페...
상속을 고려한 설계와 문서화 상속용 클래스는 재정의할 수 있는 메서드들을 내부적으로 어떻게 이용하는지(자기사용) 문서로 남겨야한다. 간단히 말하면 재정의 가능 메서드를 호출할 수 있는 모든 상황을 문서로 남겨야한다. [상속 문서화 주요내용] 재정의 가능여부 호출 순서 호출 결과의 영향 API 문서의 메서드 설명 끝에서 종종 Implementation R...
자바 제공 다중 구현 메커니즘 자바가 제공하는 다중구현 메커니즘은 추상클래스와 인터페이스 두가지다. 자바8부터 인터페이스도 디폴트 메서드를 제공할 수 있게되어, 이제 두 메커니즘 모두 인스턴스 메서드를 구현형태로 제공할 수 있다. 추상클래스와 인터페이스의 차이 추상클래스가 정의한 타입을 구현하는 클래스는 반드시 추상 클래스의 하위 클래스가 되어야한다. ...
인터페이스에 메서드 추가 자바 8 전에는 기존 구현체를 깨뜨리지 않고 인터페이스에 메서드를 추가할 방법은 존재하지 않았다. 자바 8부터 디폴트 메서드를 통해서 기존 인터페이스에 메서드를 추가할 수 있게 되었다. 디폴트 메서드를 선언하면, 그 인터페이스를 구현한 후 디폴트 메서드를 재정의하지 않은 모든 클래스에서 디폴트 구현이 쓰이게 된다. 단, 이렇게 ...
인터페이스 사용용도 인터페이스는 자신을 구현한 클래스의 인스턴스를 참조할 수 있는 타입 역할을 한다. 달리 말하면 클래스가 어떤 인터페이스를 구현한다는 것은 자신의 인스턴스로 무엇을 할 수 있는지를 클라이언트에게 얘기하주는 것이다. 인터페이스는 반드시 위 용도로만 사용이 되어야한다. 상수 인터페이스 상수 인터페이스란 메서드없이 상수를 뜻하는 필드로만...
태그 달린 클래스의 정의 > 태그 달린 클래스란 두가지 이상의 의미를 표현할 때 그 중 현재 표현하는 의미를 태그값으로 알려주는 클래스를 말한다. 태그 달린 클래스의 단점 태그 달린 클래스에는 여러 단점이 있다. 열거 타입 선언, 태그 필드, switch문 등 쓸데없는 코드가 많다. 여러 구현이 한 클래스에 혼합돼 있어서 가독성이 나쁘다. 다른 의미를 위...
중첩 클래스(nested class) 정의 > 다른 클래스 안에 정의된 클래스를 말한다. 중첩 클래스는 자신을 감싼 바깥 클래스에서만 사용되어야 한다. 중첩 클래스가 바깥 클래스 이외의 쓰임새가 있다면 톱레벨 클래스로 만들어야 한다. 중첩 클래스를 사용함으로써 불필요한 노출을 줄여 캡슐화를 할 수 있고 가독성 좋고 유지보수하기 좋은 코드를 작성할 수 있다...
톱레벨 클래스는 한파일에 하나만 담자 톱레벨 클래스를 여러개 선언하면 이득은 없고 심각한 위험만 발생할 수 있다. 한 클래스를 여러개로 정의할 수 있으며, 그 중 어느것을 사용할지는 어느 소스파일을 먼저 컴파일하냐에 따라 달라지기 때문이다. 톱레벨 클래스 중복정의 [Utensil과 Dessert를 참조하는 Main 클래스] 이제 아래 파일을 만들어보...