작성자: nobaksan

#011 열거형(Enum)과 주석(Annotation) 두번째

JAVA
작명 패턴보다는 주석(annotation)을 사용하자 What is the Annotation? 어노테이션은 일종의 메타 정보를 컴파일러에게 제공할 수 있는 문법이다. // 나 /**/ 등으로 적는 문법은 컴파일러는 알아먹을 수 없고 사람, 정확히는 프로그래머에게 이 코드는 이러저러한 코드다…라고 정보를 주는 문법이지만 어노테이션은 컴파일러에게 메타 정보를 주는 문법이다. 물론 잘 쓴 어노테이션은 프로그래머에게도 정보를 줄 수 있다. 참고 ## 메타 정보 메타데이터 (metadata)란 데이터(data)를 위한 데이터다. 어떤 데이터 즉 구조화된 정보를 분석, 분류하고 부가적 정보를 추가하기 위해 그 데이터 뒤에 함께 따라가는 정보를 말한다. 이를테면, 디지털 카메라에서는 사진을 찍어 기록할 때마다 카메라 자체의 정보와 촬영 당시의 시간, 노출, 플래시 사용 여부, 해상도, 사진 크기 등의 사진 정보를 화상 데이터와 같이 저장하게 되어 있다. 이러한 데이터를 분석하여 이용하면 그 뒤에 사진을 적절하게 정리하거나 다시 가공할 때에 아주 유용하게 쓸 수 있는 정보가 된다. 어노테이션 문법 아마 일반적으로 제일 많이 볼 수 있는 어노테이션은 @Override 일것이다. @Override public void xxx() { ... } 어노테이션의 선언 방법부터 살펴보자. 어노테이션은 @interface 타입으로 선언하며 뒤에 이름이 온다. 만일 TODO 라는 작업이라는 메타 정보를 제공하는 어노테이션을 선언한다면, 이러한 문법이 된다. public @

#010 열거형(Enum)과 주석(Annotation)

JAVA
자바 1.5 배포판에는 enum 타입이라는 새로운 클래스와 annotation이라는 새로운 인터페이스가 추가되었다. 이 장에서는 새로운 타입들을 잘 사용할 수 있는 방법을 설명한다. int 상수 대신 enum을 사용하자 int 상수에 비해 enum 타입은 훨씬 더 가독성이 좋고, 안전하며, 강력하다. // int enum 패턴 - 너무 빈약하다! public static final int APPLE_FUJI = 0; public static final int APPLE_PIPPIN = 1; public static final int APPLE_GRANNY_SMITH = 2; public static final int ORANGE_NAVEL = 0; public static final int ORANGE_TEMPLE = 1; public static final int ORANGE_BLOOD = 2; int enum 패턴의 단점 – 타입 안전을 보장하는 방법이나 편리하게 사용할 수 있는 방법을 제공하지 않는다. (예. 오렌지를 인자로 받는 메소드에 사과를 전달하고 오렌지와 사과를 == 연산자로 비교해도 컴파일 에러가 나지 않는다) – int enum 상수와 연관된 int 값이 변경되면 클라이언트 코드를 다시 컴파일 해야 한다. – int enum 상수를 출력 가능한 문자열로 쉽게 바꾸는 방법도 없다. public enum Apple {FUJI, PIPPIN, GRANNY_SMITH} public enum Orange {NAVEL, TEMPLE, BL

#009 제네릭 두번째

JAVA
제네릭 메소드를 애용하자 // 원천 타입을 사용 - 바람직하지 않다! (항목 23) public static Set union(Set s1, Set s2) { // 경고 - Set is a raw type. References to generic type Set should be parameterized Set result = new HashSet(s1); // 경고 - HashSet is a raw type. References to generic type HashSet should be parameterized result.addAll(s2); // 경고 - Type safety: The method addAll(Collection) belongs to the raw type Set. References to generic type Set should be parameterized return result; } 위의 코드는 컴파일은 되지만 경고 메시지가 나온다. 이 경고 메세지를 없애고 메소드가 타입 안전하게 만들려면, 아래와 같이 코딩한다. import java.util.*; public class Union { // 제네릭 메소드 public static Set union(Set s1, Set s2) { Set result = new HashSet(s1); result.addAll(s2); return result; } // 제네릭 메소드를 사용하는 간단한 프로그램

#007 클래스와 인터페이스 세번째

JAVA
자바에서는 클래스와 인터페이스를 설계하는데 사용할 수 있는 강력한 요소들을 제공한다. 이 장에서는 우리가 만드는 클래스와 인터페이스가 쓸모있고 강력하며 유연성이 있도록 하기 위해 도움을 주는 지침을 설명한다. 태그 (tagged) 클래스보다는 클래스 계층을 사용하자 태그(tagged) 클래스란 인스턴스들이 두 개 이상의 특성으로 분류되고 그런 특성을 나타내는 태그(tag) 필드를 갖는 클래스를 말한다. // Tagged class - 클래스 계층보다 매우 조악하다! class Figure { enum Shape { RECTANGLE, CIRCLE }; // Tag field - 이 도형의 형태 final Shape shape; // 이 필드는 shape가 RECTANGLE일 때만 사용된다. double length; double width; // 이 필드는 shape가 CIRCLE일 때만 사용된다. double radius; // circle 생성자 Figure(double radius) { shape = Shape.CIRCLE; this.radius = radius; } // rectangle 생성자 Figure(double length, double width) { shape = Shape.RECTANGLE; this.length = length; this.width = w

#006 클래스와 인터페이스 두번째

JAVA
자바에서는 클래스와 인터페이스를 설계하는데 사용할 수 있는 강력한 요소들을 제공한다. 이 장에서는 우리가 만드는 클래스와 인터페이스가 쓸모있고 강력하며 유연성이 있도록 하기 위해 도움을 주는 지침을 설명한다. 가급적 상속(inheritance)보다는 컴포지션(composition)을 사용하자 상속의 문제점 동일한 프로그래머가 서브클래스와 수퍼 클래스의 구현을 관장하는 같은 패키지 내에서 상속을 사용하는 것은 안전하다. 또한 상속을 위해 특별히 설계되고 문서화된 클래스를 확정하기 위해 상속을 사용하는 것도 안전하다. 그러나 다른 패키지에 걸쳐 일반적인 실체 클래스로부터 상속을 받는 것은 위험하다. 메소드 호출과는 달리 상속은 캡슐화를 위배한다. // 상속을 잘못 사용한 예! import java.util.*; public class InstrumentedHashSet extends HashSet { // 요소를 추가한 횟수 private int addCount = 0; public InstrumentedHashSet() { } public InstrumentedHashSet(int initCap, float loadFactor) { super(initCap, loadFactor); } @Override public boolean add(E e) { addCount++; return super.add(e); } @Override p

#005 클래스와 인터페이스

JAVA
자바에서는 클래스와 인터페이스를 설계하는데 사용할 수 있는 강력한 요소들을 제공한다. 이 장에서는 우리가 만드는 클래스와 인터페이스가 쓸모있고 강력하며 유연성이 있도록 하기 위해 도움을 주는 지침을 설명한다. 클래스와 그 멤버의 접근성을 최소화하자 잘 설계된 모듈은 외부 API 부분과 내부 구현 부분을 명쾌하게 분리하며 내부의 상세한 구현 부분 모두를 감춘다. 이 개념은 소프트웨어 설계 기본 원리 중 하나로, 정보 은닉(information hiding) 또는 캡슐화(encapsulation)라고 한다. 정보 은닉이 중요한 이유 시스템을 구성하는 모듈들 간의 결합도를 낮추어 모듈별로 개발, 테스트, 최적화, 사용 및 수정이 가능하도록 한다. 각 모듈별로 병행 개발할 수 있으므로 시스템 개발이 빨라진다. 모듈을 더 빨리 파악할 수 있다. 다른 모듈에 영향을 주지 않고 수정이 가능하므로, 유지 보수의 부담을 덜 수 있다. 정보 은닉 자체만으로 성능을 좋게 할 수 없지만 효과적인 성능 튜닝이 가능하다. (프로파일링을 통해 어떤 모듈이 문제를 유발하는지 결정되면, 다른 모듈에 영향을 주지 않고 최적화할 수 있다.) 모듈간의 결합도가 높지 않으므로 소프트웨어의 재사용성을 증가시킨다. 시스템 전체가 덜 개발 되었더라도 각 모듈별 성공 여부를 입증할 수 있으므로, 큰 시스템 개발 시 위험 부담이 줄어든다. public 클래스에서는 public 필드가 아닌 접근자(accessor) 메소드를 사용한다 // 이와 같은 클래스는 public으로 사용하면 안된다! class

#004 모든 객체에 공통적인 메소드 두번째

JAVA
12 Comparable 인터페이스의 구현을 고려하자 compareTo 메소드는 Object 클래스에 정의되어 있지 않으며(자바 1.2에 추가됨), 대신에 Comparable 인터페이스에 유일하게 존재하는 메소드이다. 이 메소드는 Object.equals 메소드와 유사한 특성을 가지는데, 차이점이라면 두 객체가 동일한지 비교하는 것과 더불어 순서까지 비교할 수 있으며, 제네릭 타입을 지원한다. 클래스에서 Comparable 인터페이스를 구현하면, 이 인터페이스에 의존하는 수많은 알고리즘 및 컬렉션 클래스들과 상호연동이 가능하다. 실제로 자바 라이브러리의 모든 값은 Comparable 인터페이스를 구현하므로, 만일 알파벳 순, 숫자 순, 날짜 순과 같은 자연율을 갖는 값 클래스를 작성한다면 반드시 Comparable 인터페이스를 구현해야 한다. compareTo 메소드의 보편적 계약 순서 판단을 위해 현재 객체(compareTo 메소드가 호출된)와 지정 객체(compareTo 메소드의 인자로 전달된)를 비교한다. 현재 객체의 값이 지정 객체보다 작으면 음수 정수값을, 같으면 0을, 크면 양수 정수값을 반환한다. 만일 지정 객체 타입이 현재 객체와 비교할 수 없는 타입이면 ClassCastException 예외를 발생시킨다. 다음 설명에서 sgn(표현식)은 signum 수학 함수를 나타내며, 표현식의 값이 음수면 -1을, 0이면 0을, 양수면 1을 반환한다. 대칭적: 모든 x, y에 대하여 sgn(x.compareTo(y)) == – sgn(y.compareTo(x))가 되도록 해

#003 모든 객체에 공통적인 메소드

JAVA
Object는 실체 클래스(concrete class)지만 원래 상속을 목적으로 설계되었다. 이 장에서는 final이 아닌 Object의 메소드(equals, hashcode, toString, clone, finalize)들을 언제 어떻게 오버라이드하는지 알려준다. 실체 클래스란? 추상 클래스와 상반되는 것으로서, 자신의 인스턴스를 생성할 수 있는 일반적인 클래스를 말한다. 8. equals 메소드를 오버라이딩 할 때는 보편적 계약을 따르자 인스턴스의 동일여부를 판정하는 euqals 메소드의 오버라이딩은 간단한 것 같지만, 잘못 구현하는 경우가 많아서 참담한 결과를 초래할 수 있다. 그런 문제를 피하는 제일 쉬운 방법은 equals 메소드를 오버라이드하지 않고 상속받은 그대로 사용하는 것이다. (여기서 equals 메소드는 Object.equals이거나, 다른 수퍼 클래스에서 Object의 equals를 이미 오버라이딩 한 것을 말한다.) equals 메소드를 오버라이드하지 않고 상속받은 그대로 사용하는 경우 1. 클래스의 각 인스턴스가 본래부터 유일한 경우 인스턴스가 갖는 값보다는 활동하는 개체임을 나타내는 것이 더 중요한 Thread와 같은 클래스가 여기에 해당된다. 그런 클래스들은 인스턴스가 갖는 값의 논리적인 비교는 의미가 없으며, 객체 참조가 같으면 동일한 것임을 알 수 있으므로 Object의 equals(== 연산자 사용)를 그냥 사용하면 된다. 2. 두 인스턴스가 논리적으로 같은지 검사하지 않아도 되는 클래스의 경우 클래스를 설계할 때, 인스턴스가 갖

#002 객체의 생성과 소멸 2번째

JAVA
객체를 언제 어떻게 생성하는지, 언제 어떻게 생성을 피해야 하는지, 적합한 방법으로 소멸되는 것을 어떻게 보장하는지, 그리고 객체 소멸에 앞서 선행되어야 하는 클린업 작업을 어떻게 관리할 것인가에 대해 설명한다. 3. private 생성자나 enum 타입을 사용해서 싱글톤의 특성을 유지하자 싱글톤이란 정확히 하나의 인스턴스만 만들어지는 클래스이다. 싱글톤은 스레드 풀이라던가, 캐시 등등 객체가 전체 프로그램에서 오직 하나만 생성되어야 하는 경우에 사용한다. 싱글톤 구현 방법 1. public static final 멤버 필드 사용 // public final를 갖는 싱글톤 public class Elvis { public static final Elvis INSTANCE = new Elvis(); private Elvis() { } public void leaveTheBuilding() { System.out.println("Whoa baby, I'm outta here!"); } // This code would normally appear outside the class! public static void main(String[] args) { Elvis elvis = Elvis.INSTANCE; elvis.leaveTheBuilding(); } } 2. static 팩토리 메소드 사용 // static 팩토리 메소드를 갖는 싱글톤 public class E

#001 객체의 생성과 소멸

JAVA
이 장에서는 객체를 언제 어떻게 생성하는지, 언제 어떻게 생성을 피해야 하는지, 적합한 방법으로 소멸되는 것을 어떻게 보장하는지, 그리고 객체 소멸에 앞서 선행되어야 하는 클린업 작업을 어떻게 관리할 것인가에 대해 설명한다. 1.생성자 대신 static 팩토리(factory) 메소드 사용을 고려하자 클래스의 인스턴스 생성방법 1. public 생성자(constructor) 2. public static 팩토리 메소드 장점: – 생성자와 달리 자기 나름의 이름을 가질 수 있다. (알다시피, 생성자는 클래스 이름과 동일해야 한다.) – 생성자와 달리 호출될 때마다 매번 새로운 객체를 생성할 필요가 없다. – 자신의 클래스 인스턴스만 반환하는 생성자와 달리, static 팩토리 메소드 자신이 반환하는 타입의 어떤 서브타입 객체도 반환할 수 있다. (유연성 제공) – 매개변수화 타입의 인스턴스를 생성하는 코드를 간결하게 해준다. 이런 식으로 중복 지정하면 타입 매개변수가 늘어나는 경우, 타이핑할 분량이 많아지고 복잡해진다. Map m = new HashMap(); 아래에 선언한 newInstance 메소드를 다음과 같이 간결한 형태로 사용할 수 있다. static 팩토리를 사용하면 컴파일러가 타입 매개변수를 해결하도록 할 수 있다. 이것을 타입 추론이라고 한다 Map m = HashMap.newInstance(); public static HashMap newInstance() { return new HashMap(); } 1.7버전부