[Basic Java] Generic
제네릭이란?
/ 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
댓글남기기