2 분 소요

제네릭이란?

/ Generic /

  • 스프링을 배우면서 제네릭에 대해 정확히 이해하지 못 했다고 생각이 들었다.
  • 기초를 제대로 이해 못 하면 어차피 응용할 때도 한계가 느껴지기 때문에 겸사겸사 정리
package Generics;  
  
public class GenericsRunner {  
    public static void main(String[] args) {  
        MyCustomList list = new MyCustomList();  
        list.addElement("A");  
        list.addElement("오직 String 타입의 데이터만 받아들임");  
        list.addElement(1); <- error
    }  
}
package Generics;  
import java.util.ArrayList;  
public class MyCustomList {  
    ArrayList<String> list = new ArrayList<>();  
    public void addElement(String element) {  
        list.add(element);  
    }  
    public void removeElement(String element) {  
        list.remove(element);  
    }  
}
  • 특정 타입만 의도적으로 사용할 수도 있겠지만 범용적으로 사용하는 것도 필요하다
  • 이 범용적으로 타입을 사용하게 만드는 방법이 제네릭

제네릭 사용

package Generics;  
import java.util.ArrayList;  
  
public class MyCustomList<T>{  
    ArrayList<T> list = new ArrayList<>();  
    public void addElement(T element) {  
        list.add(element);  
    }  
    public void removeElement(T element) {  
        list.remove(element);  
    }  
    public String toString(){  
        return list.toString();  
    }  
}
package Generics;  
  
public class GenericsRunner {  
    public static void main(String[] args) {  
        MyCustomList list = new MyCustomList();  
        list.addElement("A");  
        list.addElement("오직 String 타입의 데이터만 받아들임");  
  
        System.out.println(list.toString());  
		  -> [A, 오직 String 타입의 데이터만 받아들임]
        MyCustomList list2= new MyCustomList();  
        list2.addElement(1);  
        list2.addElement(2);  
  
        System.out.println(list2.toString());  
		    -> [1, 2]
    }  
}
  • 위 방법대로 해도 실행에는 문제가 없지만 타입을 선언 안해줘서 wrapper를 써줘야 한다.

제네릭스 타입 선언


import java.util.ArrayList;  
  
public class MyCustomList<T>{  
    ArrayList<T> list = new ArrayList<>();  
    public void addElement(T element) {  
        list.add(element);  
    }  
    public void removeElement(T element) {  
        list.remove(element);  
    }  
    public String toString(){  
        return list.toString();  
    }  
    public T get(int index){  
        return list.get(index);  
    }  
}
public class GenericsRunner {  
    public static void main(String[] args) {  
    
        MyCustomList list = new MyCustomList();  
        list.addElement("A");  
        list.addElement("오직 String 타입의 데이터만 받아들임");  
        String value = (String) list.get(0);  
        System.out.println(value);  
  
        MyCustomList list2= new MyCustomList();  
        list2.addElement(1);  
        list2.addElement(2);  
        Integer number = (Integer) list2.get(0);  
        System.out.println(number);  


        MyCustomList<Integer> list3= new MyCustomList();  
        list3.addElement(3);  
        list3.addElement(4);  
        Integer number2 = list3.get(0);  
        System.out.println(number2);  
  
    }  
}
  • list3 처럼 타입을 정해줘야 get 메소드를 사용할 떄 wrapper 클래스를 사용 안한다.
  • 로직을 이해하면 된다.

제네릭스 데이터 타입을 제한하는 방법

  • Numbers 는 integer 뿐만 아니라 long등 다양한 숫자 관련된 데이터 타입이 Numbers에 포함되어 있다.
  • 이럴 경우 String 과 같은 데이터 타입은 오류가 난다.

메서드 제네릭스

public class GenericsRunner {  
  
    static <X> X doubleValue(X value) {  
        return value;  
    }  
    static <X extends List> void duplicate(X list){  
        list.addAll(list);  
    }  
    public static void main(String[] args) {  
  
        String value1 = doubleValue(new String());  
        Integer number1 = doubleValue(5);  
        ArrayList list1 = doubleValue(new ArrayList<>());  
  
        ArrayList<Integer> numbers = new ArrayList<>(List.of(1,2,3));  
        duplicate(numbers);  
        System.out.println(numbers);
  • doubleValue 매서드처럼 타입에 상관없이 사용할 수도 있다
  • 당연히 duplicate 처럼 list를 제한해서 사용할 수도 있다.
    • list 에 종속되는 ArrayList LinkedList 다 사용 가능

와일드 카드

  • ? extends Number

	package com.in28minutes.generics;
	import com.in28minutes.generics.MyCustomList;

	public class GenericsRunner {
		static double sumOfNumberList(List<? extends Number> numbers) {
			double sum = 0.0;			
			for(Number number:numbers) {
				sum += number;
			}
			return sum;
		}

		public static void main(String[] args) {
			System.out.println(sumOfNumberList(List.of(1, 2, 3, 4, 5)));
			System.out.println(sumOfNumberList(List.of(1.1, 2.1, 3.1, 4.1, 5.1)));
			System.out.println(sumOfNumberList(List.of(1l, 2l, 3l, 4l, 5l)));
		}
	}

Console Output

More wild-cards


	package com.in28minutes.generics;
	import com.in28minutes.generics.MyCustomList;

	public class GenericsRunner {
		static void addAFewNumbers(List<? super Number> numbers) {
			numbers.add(1);
			numbers.add(1l);
			numbers.add(1.0);			
			numbers.add(1.0l);
		}

		public static void main(String[] args) {
			List<Number> numberList = new ArrayList<>();
			addAFewNumbers(numberList);
			System.out.println(numberList);
		}
	}

Console Output

참고 : https://gangnam-americano.tistory.com/47

댓글남기기