JAVA 9. 제네릭

김창민·2024년 7월 25일

BE

목록 보기
11/50

타입 안정성을 유지하면서 더 깔끔한 코드를 위해

자바 프로그래밍을 하다 보면 다음과 같은 코드를 많이 작성했을 것이다.

public String a(int a, int b) { ... }
public String a(int a, long b) { ... }
public String a(int a, String b) { ... }

반환타입, 이름, 로직 모든게 동일하지만 매개변수 타입의 차이 때문에 여러번 선언한 적이 무조건 있다.

너무 귀찮은 나머지 자바 타입의 root인 Object를 사용해서 메소드를 만들고 싶던적도 있다.
public Object a(Object a, Object b) { ... }

근데 이렇게 되면 타입 안정성이 침해받게 된다.
1. a+b가 가능한가?
2. 연산을 위해 타입 통일이 필요한데 어떻게?등등..


제네릭

위에서 동일 메소드 선언의 귀찮음 + Object를 사용해서 발생하는 많은 문제를 해결하는게 제네릭 문법이다.

  1. 기본적으로 제네릭은 클래스/메소드에 사용할 수 있다.
public class 클래스명<변수명>{
	~~
}
//////
public class Generic<T>{
	private T t;
    public T get(){return this.t;}
    public T set(T t){this.t=t;}
}
////
psvm(String[] args){
	Generic<String> sG = new Generic<>();
}

여기서 T는 컨벤션이라서 사실 아무거나 쓸 수 있는데 그냥 컨벤션이니까 T,U,V,E등을 사용하자.

Generic 클래스의 타입 변수를 T로 해서 필드, 메소드를 구현했고. 실제 인스턴스화는 아래 psvm에서 <String>으로 한게 보인다.

이렇게 인스턴스 생성시 실제 타입 변수를 넣어주면 위에 T가 String으로 행동하게 된다.

우리가 사용하는 ArrayList, Dequeue... 인스턴스 생성할때도 다 저렇게 하고 있었다. 우리는 사실 제네릭을 사용하고 있던것.

제한

  1. static 멤버에 사용이 불가능하다.
    • 이건 당연한게 static은 인스턴스가 아니라 클래스 레벨에서 관리돼서 모든 객체에 동일하게 동작해야하는데, 제네릭이면 모든 객체에 동일하게 동작할 수 없다.
  2. 제네릭 배열을 생성할 수 없다.
    • 그냥 리스트 쓰면 된다.

문법

  1. 다수의 타입 변수 사용이 가능하다.
public class Generic<T,U,E>{
	private T t;
    public U a(T t, E e){..}
}
...
Generic<Integer,Integer, String> d = new Generic();
  1. 다형성은 유지된다.
    부모가 제네릭이고 그 안에 자식클래스를 넘길 수 있다.

  2. 와일드카드를 통해 제네릭의 제한을 정할 수 있다.

  • <? extends T> : T와 그 자손들만 사용 가능
  • <? super T> : T와 그 조상들만 가능
  • <?> : 제한 없음
public class ParkingLot<T extends Car> { ... }

ParkingLot<BMW> bmwParkingLot = new ParkingLot();
ParkingLot<Iphone> iphoneParkingLot = new ParkingLog(); // error!
  1. 메서드를 스코프로 제네릭을 별도로 선언할 수 있다.
static <T> void sort(List<T> list, Comparator<? super T> c) { ... }

이 경우 해당 메서드에서만 적용되는 제네릭 타입 변수 선언이라 static에서도 가능하다.

public class Generic<T, U, E> {
		// Generic<T,U,E> 의 T와 아래의 T는 이름만 같을뿐 다른 변수
    static <T> void sort(List<T> list, Comparator<? super T> c) { ... }
}

반환 타입앞 제네릭은 이 메소드에서만 사용하기 때문에 class의 T와는 별개의 타입이다.

profile
일일 회고 : https://rlackdals981010.github.io/

0개의 댓글