티끌모아 로키산맥 🏔
search
로ᄏl
배움에 끝은 없다... 개발 또한 그러하다.
Today
Yesterday
개발서적/이펙티브 자바 (35)
아이템 28에서 이야기했듯 매개변수화 타입은 불공변(invariant)이다. 예를들어 List은 List가 하는 일을 제대로 수행하지 못하니 하위 타입이 될 수없다(리스코프 치환 원칙에 어긋난다). 하지만 때론 불공변 방식보다 유연한 무언가가 필요하다. 아이템29에서 언급된 Stack 클래스를 떠올려보자. 아래에 Stack의 public API를 나열했다. publci class Stack public Stack(); public void push(E e); public E pop(); public boolean isEmpty(); } 여기에 일련의 원소를 스택에 넣는 메서드를 추가해야 한다고 해보자. public void pushAll(Iterable src) { for (E e : src) push(..
클래스와 마찬가지로, 메서드도 제네릭으로 만들 수 있다. 매개변수화 타입을 받는 정적 유틸리티 메서드는 보통 제네릭이다. Collections의 알고리즘 메서드는 모두 제네릭이다. 제네릭 메서드 작성법은 제네릭 타입 작성법과 비슷하다. 다음은 두 집합의 합집합을 반환하는, 문제가 있는 메서드다. public static Set union(Set s1, Set s2) { Set result = new HashSet(s1); result.addAll(s2); return result; } 컴파일은 되지만 경고가 두 개 발생한다. 경고를 없애려면 이 메서드를 타입 안전하게 만들어야 한다. 메서드 선언에서의 세 집합(입력 2개, 반환 1개)의 원소 타입을 타입 매개변수로 명시하고, 메서드 안에서도 이 타입 매개..
JDK가 제공하는 제네릭 타입과 메서드를 사용하는 일은 일반적으로 쉬운 편이지만, 제네릭 타입을 새로 만드는 일은 조금 더 어렵다. 아이템 7에서 다룬 단순한 스택 코드를 다시 살펴보자. public class Stack { private Object[] elements; private int size = 0; private static final int DEFAULT_INITIAL_CAPACITY = 16; public Stack() { elements = new Object[DEFAULT_INITIAL_CAPACITY]; } public void push(Object e) { ensureCapacity(); elements[size++] = e; } public Object pop() { if (si..
배열게 제니릭 타입에는 두 가지 차이가 있다. 1. 배열은 공변(covariant)이다. 어려워 보이는 단어지만 뜻은 간단하다. Sub가 Super의 하위 타입이라면 배열 Sub[]는 배열 Super[]의 하위타입이 된다(공변, 즉 함께 변한다는 뜻이다). 반면, 제네릭은 불공변(invariant)이다. 즉, 서로 다른 타입 Type1과 Type2가 있을 때, List은 List의 하위 타입도 아니고 상위 타입도 아니다. 이것만 보면 제네릭에 문제가 있다고 생각할 수 있지만, 문제가 있는 쪽은 리스트가 아니라 오히려 배열 쪽이다. 다음은 문법상 허용되는 코드다. Object[] objectArray = new Long[1]; objectArray[0] = "타입이 달라 넣을 수 없다."; // Array..
제네릭을 사용하기 시작하면 수많은 컴파일러 경고를 보게 될 것이다. 비검사 형변환 경고, 메서드 호출 경고, 비검사 매개변수화 가변인수 타입 경고, 비검사 변환 경고 등이다. 제네릭에 익숙해질수록 마주치는 경고 수는 줄겠지만 새로 작성한 코드가 한번에 깨끗하게 컴파일되리라 기대하지는 말자. 대부분의 비검사 경고는 쉽게 제거할 수 있다. 코드를 다음처럼 잘못 작성했다고 해보자. Set exaltation = new HashSet(); 그러면 컴파일러는 무엇이 잘못됐는지 친절하게 알려줄 것이다. (javac 명령줄인수에 -Xlint:uncheck 옵션을 추가해야 한다). 컴파일러가 알려준대로 수정하면 경고가 사라진다. 사실 컴파일러가 알려준 타입 매개변수를 명시하지 않고, 자바 7부터는 지원하는 다이아몬드 ..
클래스와 인터페이스 선언에 타입 매개변수(type parameter)가 쓰이면, 이를 제네릭 클래스 혹은 제네릭 인터페이스라 한다. List 인터페이스는 원소의 타입을 나타내는 타입 매개변수 E를 받는다. 그래서 이 인터페이스의 완전한 이름은 List 지만, 짧게 그냥 List라고도 자주 쓰인다. 제네릭 클래스와 제네릭 인터페이스를 통틀어 제네릭 타입(generic type)이라 한다. 각각의 제네릭 타입은 일련의 매개변수화 타입(parameterized type)을 정의한다. 먼저 클래스 이름이 나오고, 이어서 꺾쇠괄호 안에 실제 타입 매개변수들을 나열한다. 마지막으로, 제네릭 타입을 하나 정의하면 그에 딸린 로 타입(raw type)도 함께 정의된다. 로 타입이란 제네릭 타입에서 타입 매개변수를 전혀..