강좌 Course 2. Part 2. ch2 요약
ArrayList는 Object[]을 사용하기 때문에 한 가지 타입의 객체만을 넣으려고 해도 다른 타입의 객체를 넣을 수 있어 안정성이 떨어진다.
이를 보완하기 위해 등장한 것이 제네릭으로, 자바에서 데이터타입을 일반화하는 방법이다. 제네릭을 사용하면 컬렉션, 메서드, 클래스 등에서 사용하는 데이터타입을 런타임 시에(=실행시) 결정할 수 있다. 제네릭을 사용하면 조금 더 안정적이고 유연하게 코드를 짤 수 있다.
또, 제네릭 타입을 선언할 때 어떤 데이터타입이 들어올지 정해져있지 않아 일반적인 메서드나 클래스를 작성할 수 있어 재사용성이 높아진다.
제네릭은 <> 기호를 사용하여 표시한다.
// 제네릭을 사용한 ObjectArr 클래스
public class ObjectArr<T> { // 제네릭으로 array 타입 미정
private T[] array;
private int size;
public ObjectArr(int size) {
array = (T[]) new Object[size]; // Object 배열로 받고 T[]로 다운캐스팅
}
public void set(int index, T value) {
array[index] = value;
size++; // set 실행한 횟수가 size
}
public T get(int index) {
return array[index];
}
public int size() {
return size;
}
}
ObjectArr에 String을 넣어보면, 잘 작동한다. 다른 객체도 가능하다.
public class GenericTest {
public static void main(String[] args) {
ObjectArr<String> arr = new ObjectArr<>(5);
arr.set(0,"a");
arr.set(1,"b");
arr.set(2,"c");
arr.set(3,"d");
for (int i=0;i<arr.size();i++){
System.out.println(arr.get(i));
}
System.out.println(arr.size());
}
}
자바 제네릭에서 멀티 타입 파라미터는 제네릭타입을 여러 개 선언하여 사용하는 것이다. 맵에서 key와 value를 사용하는 것처럼 2개 혹은 그 이상을 선언하여 받을 수 있다.
* K, V를 사용하는 것은 그저 convention일 뿐 다른 이름으로 설정하여도 된다.
사진에서 보듯 Pair에서 K, V로 받은 제네릭 멀티타입 파라미터를 PairGenericTest에서는 String과 Integer로 받을 수 있었다.
제한된 타입 파라미터는 받을 수 있는 타입을 특정해둔 것으로, 제네릭 클래스나 메서드에서 사용할 수 있는 타입을 제한할 수 있다.
아래의 AverageCalculator에서 볼 수 있듯, 제네릭 타입 파라미터를 넘겨주는 부등호 안에 extends Number처럼 제네릭을 제한할 수 있다. Numbers를 상속한 타입만 받을 수 있다는 말로, String이나 다른 타입이 오면 컴파일 오류가 나게 된다.
public class AverageCalculator <T extends Number> {
private T[] numbers;
public AverageCalculator(T[] numbers){
this.numbers=numbers;
}
public double calculateAvg(){
double sum = 0.0;
for(T num:numbers){
sum += num.doubleValue();
}
return sum/ numbers.length;
}
}
만든 AverageCalculator를 사용해보았다.
Integer와 Double을 넣으니 잘 돌아갔다.
public class GenericLimitTest {
public static void main(String[] args) {
Integer[] integers = {10,20,30,40,50};
Double[] doubles = {1.0,2.0,3.0,4.0,5.0};
AverageCalculator<Integer> intCal = new AverageCalculator<>(integers);
AverageCalculator<Double> dblCal = new AverageCalculator<>(doubles);
double intAvg = intCal.calculateAvg();
double dblAvg = dblCal.calculateAvg();
System.out.println(intAvg);
System.out.println(dblAvg);
}
}