본문 바로가기
Programming/Java

[자바/Java] 제네릭(Generic)

by 코딩하는 랄로 2023. 10. 12.
728x90

제네릭(Generic)이란

자바를 조금씩 알아가고 있는 사람에겐 제네릭이라는 키워드는 생소할 수 있다. 하지만, 이미 수없이 우리는 제네릭을 마주해왔음을 이번 글을 통해 알 수 있을 것이다.

 

제네릭이란 데이터의 타입을 클래스 내부에서 지정하는 것이 아닌 외부에서 사용자에 의해 지정되는 것을 의미한다. 즉, 사용자에 의해 어떤 타입으로 지정이 되는 해당 클래스의 메소드는 동일한 기능을 하는 것이다.

 

이러한 제네릭이 적용된 클래스는 익히 알고 있는 ArrayList, LinkedList 등이 있다. 예를 들어, ArrayList를 통해 특정 타입의 배열을 생성하고 싶을 때 다음과 같이 생성을 한다.

 

// Integer 배열
ArrayList<Integer> intList = new ArrayList<>();

// String 배열
ArrayList<String> stringList = new ArrayList<>();

// 클래스 타입을 가지는 배열
class Point {
    ...
}

ArrayList<Point> classList = new ArrayList<>();

 

<> 안에 어떠한 타입을 넣는 ArrayList 클래스는 해당 타입을 가지는 객체를 생성하여 여러 기능을 수행할 수 있는 배열로서 동작한다.

 

이처럼 사용자가 원하는 타입으로 클래스 타입을 지정하여 주는 것이 제네릭이다.

 

 

 

제네릭의 장점

사용자가 클래스의 타입을 지정하게 함으로써 얻을 수 있는 장점으로는 다음과 같다.

 

  • 제네릭을 사용아면 잘못된 타입이 들어올 수 있는 경우를 컴파일 단계에서 방지
// Integer 타입의 ArrayList 생성
ArrayList<Integer> intList = new ArrayList<>();

intList.add(1);  // 1 이 Integer 객체로 auto boxing되어 intList에 저장
intList.add("1"); // String 타입이므로 에러 발생(IDE에서는 빨간줄이 뜸)
  • 클래스 외부에서 타입을 지정해주기 때문에 별도로 타입을 체크하고 변환해줄 필요가 없다. 즉, 코드를 관리하기 용이

 

  • 비슷한 기능을 지원하는 경우, 코드의 재사용성이 높아진다.(ArrayList<Integer>, ArrayList<String> 각각의 타입에 해당하는 ArrayList 클래스를 만들 필요 X)

 

 

 

제네릭 클래스 생성

기본적으로 제공되는 여러 제네릭 클래스 이외에도 사용자 또한 제네릭 클래스를 생성하고 사용할 수 있다. 클래스에서는 일반 클래스 또는 인터페이스 이름 뒤에 <> 부호를 붙고 타입 파라미터를 선언해주는 것으로 생성할 수 있다.

 

public class GenericEX <T> {...}
public interface GenericEX2 <E> {...}

 

타입 파라미터는 위의 예시에서 보았듯이 정해진 규칙은 없지만 사용자들끼리 암묵적으로 정해진 규칙이 있다.

  • <T> : Type
  • <E> : Element
  • <K> : Key
  • <N> : Number
  • <V> : Value
  • <R> : Result

또한, 제네릭 클래스에서 사용되는 타입은 기본 타입(primitive type)은 사용할 수 없고, 객체(Object) 타입만 사용할 수 있다.

 

그렇기 때문에 기본타입을 사용하고 싶을 경우, 기본타입의 Wrapper 클래스를 사용하여야 한다. 또한 클래스 내에 static 필드에서는 generic이 사용불가능 하다.

 

class Test<T, U> {
	T item1;
	U item2;

//	static T item3;   // static 필드에는 generic 사용 불가.

	public Test(T item1, U item2){
		this.item1 = item1;
		this.item2 = item2;
	}

	public void display(){
		System.out.println("item1: " + item1);
		System.out.println("item2: " + item2);
	}
}

pubic class Main {
    public static void main(String[] args) {
        Test<Integer, String> t1 = new Test<>(123, "Hello");
        t1.display();
        //123
        //hello
        
        Test<Integer, Double> t2 = new Test<>(111, 3.14);
        t2.display();
        //111
        //3.14
    }
}

 

 

 

제네릭 메소드 생성

제네릭 메소드는 메소드의 선언부에 적은 타입 파라미터로 '리턴 타입'이나 '파라미터 타입' 이 정해지는 메소드이다. 제네릭 메소드의 경우 static 메소드로도 가능하다.

 

public static <T> void test1(T t){}

public <T> T test2(T param){}

public static <T> Test<T> test3(T t){
    Test<T> test = new Test<>();
    test.setTest(t);
    return test;
}


class Test<T> {
	T test;

	public void setTest(T test){
		this.test = test;
	}
}

 

위의 예시에서 알 수 있듯이, 제네릭 클래스 밖에서 특정 메소드에 제네릭을 사용하고자 한다면 리턴 타입을 전에 제네릭 메소드임을 명시해주어야 한다. (제네릭 클래스는 필요X)

 

그 외에 함수의 리턴 타입 또는 파라미터 타입을 제네릭으로 지정하여 사용하면 된다.

 

 

 

제한된 제네릭 & 와일드 카드

제네릭을 사용하면 클래스나 메소드는 어떤 객체의 타입이든 가질 수 있다. 하지만 만약 숫자만을 다루는 클래스를 만들고 그에 관한 기능을 구현을 했는데 String타입이 들어온다면 해당 기능들에서 오류가 발생하는 상황이 발생 할 수 있다.

 

이럴 때, 제네릭을 와일드 카드를 통해서 특정 타입으로 제한하는 것이 가능하다. 와일드 카드는 ?(물음표)를 통해 표시한다.

 

일반적으로 와일드 카드만 사용한다면 일반 타입파라미터와 같이 동작하지만 extends와 super 키워드를 같이 사용한다면 제네릭을 제한할 수 있다.

 

public class WildCardEx { 
	//일반 타입 파라미터와 똑같이 동작
    public void printList(List<?> list) { 
        for(Object obj : list) { 
            system.out.println(obj + " ");
        }
    }
    
    //? extends T : 상한 경계
    // T 클래스 타입을 포함한 자식 클래스로만 타입을 지정할 수 있다.
    public int sum(List<? extends Number> list){
    	int sum =0;
        for(Number i : list) { 
            sum += i.doubleValue();
        }
        return sum;
    }
    
    //? super T : 하한 경계
    // T 클래스 타입을 포함한 부모 클래스로만 타입을 지정할 수 있다.
    public List<? super Integer> addList(List<? super Integer> list) {
        for(int i= 1; i<5; i++) {
    	    list.add(i);
        }
    
        return list;
   	}
}

 

 

 

728x90

'Programming > Java' 카테고리의 다른 글

[자바/Java] Collection2 - 사용예제  (0) 2023.10.13
[자바/Java] Collection1 - 개념  (1) 2023.10.13
[자바/Java] Wrapper 클래스  (0) 2023.10.12
[자바/Java] Time 패키지의 클래스  (0) 2023.10.11
[자바/Java] Date 클래스  (1) 2023.10.10