Search

자바의 정석 Chapter 12 : 제네릭스

제네릭스(Generics)
컴파일 시 타입을 체크(강화)해주는 기능(complie-time type check) (jdk 1.5부터)
객체의 타입 안정성을 높이고 형변환의 번거로움을 줄여준다
장점
타입 안정성을 제공한다 (ClassCastException 방지)
타입체크와 형변환을 생략할 수 있으므로 코드가 간결해진다
타입 변수(=타입 매개변수)
제네릭 클래스를 작성할 때 Object타입(일반 클래스) 대신 타입 변수(E)를 선언해서 사용
객체를 생성 시 타입 변수(E) 대신 실제 타입(Tv)를 지정(대입)
참조 변수와 생성자의 대입된 타입은 일치해야 한다
(jdk 1.7부터 생성자에 타입 지정은 일치하다는 가정 하에 생략 가능하다)
제네릭 클래스 간의 다형성은 성립 (여전히 대입된 타입은 일치해야 한다)
매개변수의 다형성도 성립
Iterator<E>
클래스를 작성할 때 Object 타입 대신 T와 같은 타입 변수를 사용
HashMap<K,V>
여러 개의 타입 변수가 필요한 경우 콤마(,)를 구분자로 선언
제한된 제네릭 클래스
extends로 대입할 수 있는 타입을 제한
인터페이스인 경우에도 extends를 사용
제네릭스의 제약
타입 변수에 대입은 인스턴스 별로 다르게 가능
static 멤버에 타입 변수 사용 불가 (static 멤버는 모든 인스턴스에 공통이기 때문에)
배열 생성할 때 타입 변수 사용 불가. 타입 변수로 배열 선언은 가능
와일드카드 <?>
하나의 참조 변수로 대입된 타입이 다른 객체를 참조 가능
<? extends T> : 와일드 카드의 상한 제한. T와 그 자손들만 가능
<? super T> : 와일드 카드의 하한 제한. T와 그 조상들만 가능
<?> : 제한 없음. 모든 타입이 가능. <? extends Object>와 동일
메서드의 매개변수에 와일드 카드를 사용
제네릭 메서드
제네릭 타입이 선언된 메서드(타입 변수는 메서드 내에서만 유효)
클래스의 타입 매개변수<T>와 메서드의 타입 매개변수 <T>는 별개
메서드를 호출할 때마다 타입을 대입해야함(대부분 생략 가능)
메서드를 호출할 때 타입을 생략하지 않을 때는 클래스 이름 생략 불가
와일드 카드 vs 제네릭 메서드
와일드 카드 : 하나의 참조변수로 서로 다른 타입이 대입된 여러 제네릭 객체를 다루기 위한 것
제네릭 메서드 : 메서드를 호출할 때마다 다른 제네릭 타입을 대입할 수 있게 한 것
제네릭 타입의 형변환
제네릭 타입과 원시 타입 간의 형변환은 바람직 하지 않다 (경고 발생)
와일드 카드가 사용된 제네릭 타입으로는 형변환 가능
제네릭 타입의 제거
컴파일러는 제네릭 타입을 제거하고 필요한 곳에 형변환을 넣는다
1.
제네릭 타입의 경계(bound)를 제거 (<T> → Object)
2.
제네릭 타입 제거 후에 타입이 불일치하면 형변환을 추가
3.
와일드 카드가 포함된 경우 적절한 타입으로 형변환 추가
열거형(enum)
관련된 상수들을 같이 묶어 놓은 것. Java는 타입에 안전한 열거형을 제공한다
열거형 정의와 사용
정의 : enum 열거형이름 { 상수명1, 상수명2, ... }
열거형 타입의 변수를 선언하고 사용하는 방법
열거형 상수의 비교에 ==와 compareTo() 사용가능
열거형의 조상 - java.lang.Enum 클래스
모든 열거형은 Enum의 자손이며, 아래의 메서드를 상속 받는다
values(), valueOf()는 컴파일러가 자동으로 추가해준다
values() : Direction[] dArr = Direction.values();
valueOf() : Direction d = Direction.valueOf(”WEST”);
열거형에 멤버 추가하기
불연속적인 열거형 상수의 경우 원하는 값을 괄호()안에 적는다 (여러개 가능)
괄호()를 사용하려면 인스턴스 변수와 생성자를 새로 추가해줘야 한다
열거형의 생성자는 묵시적으로 private이므로 외부에서 객체생성 불가
애너테이션
주석처럼 프로그래밍 언어에 영향을 미치지 않으며 유용한 정보를 제공
애너테이션의 사용 예시
표준 애너테이션
Java에서 제공하는 애너테이션
@Override
오버라이딩을 올바르게 했는지 컴파일러가 체크하게 한다
오버라이딩을 할 때 메서드 이름을 잘못 적는 실수를 하는 경우가 많다
오버라이딩 할 때는 메서드 선언부 앞에 @Override를 붙이자
@Deprecated
앞으로 사용하지 않을 것을 권장하는 필드나 메서드에 붙인다
ex. Date 클래스의 getDate()
@Deprecated가 붙은 대상이 사용된 코드를 컴파일하면 나타나는 메시지
@FunctionalInterface
함수형 인터페이스에 붙이면 컴파일러가 올바르게 작성했는지 체크
함수형 인터페이스에는 하나의 추상메서드만 가져야 한다는 제약이 있음
@SuppressWarnings
컴파일러의 경고메시지가 나타나지 않게 억제한다
괄호()안에 억제하고자하는 경고의 종류를 문자열로 지정
둘 이상의 경고를 동시에 억제하려면 다음과 같이 한다
‘-Xlint’ 옵션으로 컴파일하면 경고메시지를 확인할 수 있다. 괄호[]안이 경고의 종류
메타 애너테이션
‘애너테이션을 위한 애너테이션'으로 애너테이션을 만들 때 사용한다
메타 애너테이션은 java.lang.annotation 패키지에 포함된다
@Target
애너테이션을 정의할 때 적용대상 지정에 사용한다
@Retention
애너테이션이 유지되는 기간을 지정하는데 사용
컴파일러에 의해 사용되는 애너테이션의 유지 정책은 SOURCE이다
실행 시에 사용 가능한 애너테이션의 정책은 RUNTIME이다
@Documented, @Inherited
javadoc으로 작성한 문서에 포함시키려면 @Documented를 붙인다
애너테이션을 자손 클래스에 상속하고자 할 때 @Inherited를 붙인다
@Repeatable
반복해서 붙일 수 있는 애너테이션을 정의할 때 사용
@Repeatable이 붙은 애너테이션은 반복해서 붙일 수 있다
@Repeatable인 @ToDo를 하나로 묶을 컨테이너 애너테이션도 정의해야한다
애너테이션 타입 정의하기
애너테이션을 직접 만들어 쓸 수 있다
애너테이션의 메서드는 추상 메서드이며 애너테이션을 적용할 때 지정 (순서 상관X)
애너테이션의 요소
적용 시 값을 지정하지 않으면 사용될 수 있는 기본값 지정 가능 (null 제외)
요소가 하나이고 이름이 value일 때는 요소의 이름 생략가능
요소의 타입이 배열인 경우 괄호{}를 사용해야 한다
모든 애너테이션의 조상 - java.lang.annotation.Annotation
Annotation은 모든 애너테이션의 조상이지만 상속은 불가
사실 Annotation은 인터페이스이다
마커 애너테이션 - Marker Annotation
요소가 하나도 정의되지 않은 애너테이션
애너테이션 요소의 규칙
애너테이션의 요소를 선언할 때 아래의 규칙을 반드시 지켜야 한다
요소의 타입은 기본형, String, enum, 애너테이션, Class만 허용됨
괄호()안에 매개변수를 선언할 수 없다
예외를 선언할 수 없다
요소를 타입 매개변수로 정의할 수 없다