Java/java study

Java - 제네릭(Generics)

jddng 2022. 4. 3. 22:26
728x90
반응형

 

 

제네릭(Generics)

  • 제네릭 사용법
  • 제네릭 - 바운디드 타입
  • 제네릭 - 와일드카드
  • 제네릭 메서드

 

 

 

 

제네릭(Generics)란?

 

 지네릭스는 다양한 타입의 객체를 다루는 메서드나 컬렉션 클래스에 컴파일 시의 타입 체크를 해주는 기능이다. 객체의 타입을 컴파일 시에 체크하기 때문에 객체의 타입 안정성을 높이고 형 변환의 번거로움을 줄일 수 있다.

 

 

- 타입 안정성

 의도하지 않은 타입의 객체가 저장되는 것을 막고, 저장된 객체를 꺼내올 때 원래의 타입과 다른 타입으로 잘못 형 변환되어 발생할 수 있는 오류를 줄여준다.

 

 

- 제네릭을 사용하는 이유

  • 제네릭 타입을 사용함으로써 잘못된 타입이 사용될 수 있는 문제를 컴파일 과정에서 제거할 수 있기 때문
  • 자바 컴파일러는 코드에서 잘못 사용된 타입 때문에 발생하는 문제점을 제거하기 위해 제네릭 코드에 대해 강한 타입 체크를 한다.
  • 실행 시 타입 에러가 나는 것보다 컴파일 시에 미리 타입을 강하게 체크하여 에러를 사전에 방지할 수 있다.
  • 제네릭 코드를 사용하면 타입을 국한하기 때문에 요소를 찾아올 때 타입 변환을 할 필요가 없어 프로그램 성능이 향상되는 효과를 얻을 수 있다.

 


 

제네릭 사용법

 

 - 제네릭 클래스 선언

public class Box<T> {

    private T type;
    
    public void set(T type) { this.type = type }
    public T get() { return type; }
}
  • T를 타입 변수(Type variable) 이라 한다.
  • 타입 변수는 상황에 맞는 의미 있는 문자를 선택하여 사용할 수 있다.
       - T : Type, E : Element, K : Key, V : Value
  • 과거에는 Object로 다양한 종류의 타입을 다룰 때 사용했지만 타입 체크 시 문제가 발생했다.

 

- 제네릭 클래스 사용

Box<String> box = new Box();
// 타입 변수에 String을 전달하였으므로 아래와 같다.
public class Box {

    private String type;
    
    public void set(String type) { this.type = type }
    public String get() { return type; }
}

Box<int> box = new box();
// 타입 변수에 int를 전달하였으므로 아래와 같다.
public class Box {

    private int type;
    
    public void set(int type) { this.type = type }
    public int get() { return type; }
}

 

 

- 지네릭스의 제한

  • 모든 객체에 대해 동일하게 동작해야 하는 static멤버에 타입 변수 T를 사용할 수 없다.
  • 지네릭 타입의 배열을 생성할 수 없다.(컴파일러가 컴파일 시점에 타입 T 가 무엇인지 알아야 하기 때문)

 

 


 

제네릭 주요 개념 - 바운디드 타입(Bounded Type)

 

  • 바운디드 타입은 특정 타입의 서브 타입으로 제한한다.
  • 클래스나 인터페이스 설계할 때 가장 흔하게 사용할 정도로 많이 볼 수 있는 개념이다.

 

public class Box<T extends S> {

	...
}
  • 타입 변수 T는 S의 서브 타입만 허용한다.

 

제네릭 주요 개념 - 와일드카드(WildCard)

 

- Unbounded WildCard

  • ? 와 같은 형태로 물음표만 가지고 정의한다.( ex. List<?> )
  • 내부적으로 Object로 정의되어 있기 때문에 모든 타입의 인자를 받을 수 있다.
  • 타입 파라미터에 의존하지 않는 메서드만을 사용하거나 Object 메서드에서 제공하는 기능으로
    충분한 경우 사용한다.
  • Object 클래스에서 제공되는 기능을 이용하여 구현하는 메서드에서 사용
  • 타입 파라미터에 의존적이지 않는 일반 클래스의 메서드를 사용하는 경우에 사용
    ex) List, clear, List, size 등

 

- Upper Bounded Wildcard

  • 특정 클래스의 자식 클래스만을 인자로 받을 때 사용한다.
  • 사용할 수 있는 기능은 특정 클래스에서 정의된 기능만 사용할 수 있다.
    ex) List<? extends Skill>

 

- Lower Bounded Wildcard

  • 특정 클래스의 부모 클래스만을 인자로 받을 수 있다.
    ex) List<? supper Skill>

 

지네릭 메서드

 

  • 메서드 선언부에 지네릭 타입이 선언된 메서드를 지네릭 메서드라 한다.
  • static 멤버에는 타입 매개변수를 사용할 수 없지만, 메서드에는 사용이 가능하다.
  • 지네릭 타입의 선언 위치는 반환 타입 바로 앞이다.
static <T> void sort(List<T> list, Comparator<? super T> c)

 

  • 제네릭 클래스에 정의된 타입 매개변수와 제네릭 메서드에 정의된 타입 매개변수는
    서로 다른 타입 변수다.(같은 타입 문자 T를 사용해도 같은 타입 변수가 아니다)
class FruitBox<T>{
	...
	static <T> void sort(List<T> list, Compatrator<? super T> c){
		...
	}
}

 

 

예시

public static void printAll(
			ArrayList<? extends Product> list,
			ArrayList<? extends Product> list2){
    
	for(Unit u : list){
		System.out.println(u);
	}
}


// 지네릭 메서드로 변경

public static void printAll(
			ArrayList<? extends Product> list,
			ArrayList<? extends Product> list2){
            
	for(Unit u : list){
		System.out.println(u);
	}
}

 

728x90
반응형