Generic

EUNJI LEE·2023년 4월 12일
0

JAVA

목록 보기
12/12
post-custom-banner

제네릭(Generic)

제네릭은 자바에서 동적 타입을 지정한다. 타입을 선언하면서 지정하는 것이 아닌 계속해서 변경할 수 있는 것을 말한다. <제네릭타입 변수명> 을 클래스 뒤에 삽입해서 사용할 수 있다.

💡 타입 지정 시점?
제네릭 클레스객체를 생성하는 시점에서 타입을 지정하고 제네릭 메소드메소드를 호출하는 시점에서 데이터 타입을 지정하는 것이다.

객체를 생성하려고 할 때, 받을 매개변수의 타입과 갯수가 자주 바뀐다면 다양한 경우의 수에 맞는 매개변수 생성자가 만들어져야 한다. 로직 자체는 같지만 타입이 달라질 때마다 매번 새로운 클래스, 생성자를 만들어야한다는 불편함을 제네릭을 사용하면 해결할 수 있다.

물론 객체 타입을 최상위 클래스인 Object로 선언해서 다양한 값을 받아낼 수 있지만 이런 경우 데이터를 불러올 때도 Object로 반환해서 받아오기 때문에 다른 타입을 사용할 때는 매번 형변환이 필요하다는 불편함이 있다.

또한 타입을 잘못 저장했을 때 캐스팅 오류가 발생하는 경우가 생긴다. 이때, 제네릭을 사용하면 문법 오류가 발생해서 실행 전에 각 타입이 맞게 들어가고 있는지 확인할 수 있다.

public class GenericBasic<T,E> {
	private T data;
	private E element; //객체를 지칭할 때 E를 자주 사용

	public GenericBasic(T data, E element) {
		this.data=data;
		this.element=element;
	}
}

💡 보통 제네릭 타입과 변수 명은 아래와 같이 표현한다.

TType
KKey
VValue
NNumber
EElement

다수의 제네릭 타입을 사용할 수 있고 해당 클래스의 set, get메소드들도 매개변수, 반환 타입으로 제네릭을 갖는다.

제네릭 타입으로 생성한 클래스의 타입 지정

public class GenericController {
	public static void main(String[] args) {
		GenericBasic<String,Date> gb=new GenericBasic();
		//T의 타입을 지정해주지 않아도 오류없이 실행하지만 경고메시지가 띄워진다.
		gb.setData("LEE");
	}
}

💡 위 메소드 안에 gb.setData(20); 을 사용하면 오류가 발생한다. 제네릭 String으로 타입을 지정해줬기 때문에 String만 받을 수 있게 된 것이다.
제네릭 타입 지정 시, 왼쪽에는 제네릭 타입을 지정해주고 대입 하는 쪽에 제네릭 타입을 생략해도 대입하면서 업캐스팅 되기 때문에 오류가 발생하진 않는다.

ArrayList, Set에 제네릭 활용

//ArrayList에 제네릭 타입 사용
ArrayList<Fruit> fruits=new ArrayList<>();
fruits.add(new Fruit("딸기","논산",10,10000));
fruits.add(new Fruit("사과","예산",20,35000));
for(int i=0;i<fruits.size();i++) {
	String name=fruits.get(i).getName();
	//get 반환 타입도 E, 제너릭으로 선언되어있기 때문에 내가 지정한 타입으로 바로 접근 가능
	System.out.println(name);
}

//Set에 제네릭 타입 사용
Set<Animal> animals=new HashSet();
animals.add(new Animal("코코",3.8,4,"강아지"));
animals.add(new Animal("꽥꽥이",4.6,3,"오리"));
//animals.add(new Fruit()) 제너릭 타입을 지정했기 때문에 다른 타입으로 사용할 수 없다.
Iterator <Animal> it=animals.iterator();
while(it.hasNext()) {
	Animal a=it.next();
	System.out.println(a);
}

💡 제네릭 타입으로는 모든 타입을 받을 수 있다. 특정 클래스를 타입으로 받으면 다른 타입의 클래스 타입을 받을 수 없어진다. Set을 사용할 땐 Iterator를 함께 사용하는데 이때 Iterator에도 제네릭 타입이 존재하기 때문에 타입을 지정할 수 있다.

Map에 제네릭 타입을 활용

Map<String, List<Food>> foodTable=new HashMap();
foodTable.put("a", new ArrayList());
//값을 지정하지 않아도 위에서 제너릭을 정해줬기 때문에 List안에서는 Food클래스만 저장 가능
//짜장면, 짬뽕, 탕수육 ->a 테이블 주문
foodTable.get("a").add(new Food("짜장면",8500,"중식",new Date()));
foodTable.get("a").add(new Food("짬뽕",9000,"중식",new Date()));
foodTable.get("a").add(new Food("탕수육",15000,"중식",new Date()));
//Map의 해당 key에 저장된 value를 List에 저장
List<Food> orderList=foodTable.get("a");	
orderList.forEach(food->System.out.println(food));
💡 key 값으로 String을 타입으로 받고 value 값으로 List를 타입으로 받는다. 이때 List에 제네릭을 사용해서 List에는 Food 클래스만 받아올 수 있도록 지정할 수 있다.
profile
천천히 기록해보는 비비로그
post-custom-banner

0개의 댓글