[Java] Generics - 1

19223 단어 JavaJava

자바의 정석을 통해 공부한 내용을 요약하였습니다

1. 지네릭스(Generics)란?

  • 다양한 타입의 객체를 다루는 메서드나 컬렉션 클래스에 컴파일 시의 타입 체크를 해주는 기능이다.

지네릭스의 장점
1. 타입 안정성을 제공
2. 타입체크와 형변환을 생략 -> 코드가 간결해짐

  • 즉, 지네릭스는 타입을 미리 명시해줌으로써 번거로운 형변환을 줄여준다.



2. 지네릭 클래스

class Box {
	Object item;
	
	void setItem(Object item) {
		this.item = item;
	}
	Object getItem() {
		return item;
	}
}

위와 같이 Object 타입을 사용하는 일반 클래스를 지네릭 클래스로 변경하면 다음과 같다.

class Box<T> {
	T item;
	
	void setItem(T item) {
		this.item = item;
	}
	T getItem() {
		return item;
	}
}

'T' 라는 타입변수를 사용하여 지네릭 클래스로 변경하였다.
타입 변수는 상황에 맞게 의미있는 문자를 선택해서 사용하는 것이 좋다.
기존에 Object 타입을 사용함으로써 형변환이 불가피했지만 타입 변수를 사용하여 원하는 타입을 지정하기만 하면 된다.

예를 들어 Box클래스 객체 생성 시 String 타입을 지정해주게 되면 Box클래스는 아래와 같이 정의된 것과 같다.

Box<String> b = new Box<String>();

class Box {
	String item;
	
	void setItem(String item) {
		this.item = item;
	}
	String getItem() {
		return item;
	}
}

지네릭이 도입되기 이전의 코드와 호환을 위해 지네릭 클래스를 예전 방식으로 객체를 생성하는 것을 허용하지만 경고가 발생하게 된다.
지네릭 클래스를 사용할 때는 반드시 타입을 지정해주는 것이 좋다.

Box b = new Box(); // T는 Object로 간주, 경고 발생
Box<String> b = new Box<String>(); // OK
Box<String> b = new Box<>(); // OK, JDK 1.7부터 생성자 타입 생략 가능



3. 지네릭스의 용어

Box< T> - 지네릭 클래스
T - 타입 변수 또는 타입 매개변수
Box - 원시 타입(raw type), 일반 클래스



4. 지네릭스의 제한

  • static멤버에 타입 변수를 사용할 수 없다.
  • 타입 변수는 인스턴스 변수로 간주되기 때문이다.
class Box<T>{
	static T item; // 에러
	static int compare(T t1, T t2) { //에러
		.... 
	}
}
  • 지네릭 타입의 배열을 생성하는 것도 허용되지 않는다.
  • 지네릭 배열 타입의 참조변수를 선언하는 것은 가능하다.
  • new T[10] 과 같이 배열을 생성하는 것은 안된다.
  • new 연산자는 컴파일 시점에 타입 T가 무엇인지 정확히 알지못하면 에러가 발생한다.
class Box<T>{
	T[] itemArr; // OK, T타입의 배열을 위한 참조변수
	
	T[] toArray() {
		T[] tmpArr = new T[itemArr.length]; // 에러 지네릭 배열 생성 불가
		....
		return tmpArr;
	}
}



5. 지네릭 클래스의 객체 생성과 사용

5-1. 지네릭 클래스 생성

class Box<T> {
	ArrayList<T> list = new ArrayList<T>();
	void add(T item)  { list.add(item); }
	T get(int i)      { return list.get(i); }
	int size() { return list.size(); }
	public String toString() { return list.toString();}
}
  • 위와 같이 타입변수를 사용하여 지네릭 클래스르 생성한다.

5-2. 지네릭 클래스 객체 사용

Box<Apple> appleBox = new Box<Apple>(); // OK
Box<Grape> grapeBox = new Box<Apple>(); // 에러. 타입 불일치
  • 참조변수와 생성자에 대입된 타입이 일치해야 한다.
Box<Fruit> appleBox = new Box<Apple>(); // 에러. 타입 불일치
  • 두 타입이 상속관계에 있어도 에러가 발생한다.
Box<Apple> appleBox = new FruitBox<Apple>(); // OK, 다형성
  • 두 지네릭 클래스의 타입이 상속관계에 있고 대입된 타입이 같다면 에러가 발생하지 않는다.
FruitBox<Apple> appleBox = new FruitBox<Apple>();

appleBox.add(new Apple()); 
appleBox.add(new Grape()); // 에러발생

FruitBox<Fruit> fruitBox = new FruitBox<Fruit>(); 
fruitBox.add(new Fruit()); 
fruitBox.add(new Apple()); // OK , Apple은 Fruit의 자손
  • 객체를 추가할 때 대입된 타입과 다른 타입의 객체는 추가할 수 없다.
  • 단, 타입이 부모일 경우 자손돌은 메서드의 매개변수가 될 수 있다.

좋은 웹페이지 즐겨찾기