- 대부분의 최신 프로그래밍 언어는 제네릭(Generic) 개념을 제공함
- 자바에서 제네릭을 제대로 이해하는 것은 어렵기 때문에, 먼저 제네릭을 전혀 사용하지 않고 코드를 작성한 후 코드에 제네릭을 점진적으로 도입
- 기존 방식으로는 해결이 어려운 코드 중복을 제네릭이 어떻게 해결하는지 자연스럽게 이해할 수 있도록 함
- 제네릭이 필요한 이유를 코드를 통해 학습
package generic.ex1;
public class IntegerBox {
private Integer value;
public void set(Integer value) {
this.value = value;
}
public Integer get() {
return value;
}
}
package generic.ex1;
public class StringBox {
private String value;
public void set(String object) {
this.value = object;
}
public String get() {
return value;
}
}
package generic.ex1;
public class BoxMain1 {
public static void main(String[] args) {
IntegerBox integerBox = new IntegerBox();
integerBox.set(10); //오토 박싱
Integer integer = integerBox.get();
System.out.println("integer = " + integer);
StringBox stringBox = new StringBox();
stringBox.set("hello");
String str = stringBox.get();
System.out.println("str = " + str);
}
}
integer = 10
str = hello
IntegerBox를 생성하고, 그곳에 숫자 10을 보관하고, 꺼낸 다음에 출력함int가 Integer로 자동 변환됨StringBox를 생성하고 그곳에 문자열 "hello"를 보관하고, 꺼낸 다음에 출력함Double, Boolean을 포함한 다양한 타입을 담는 박스가 필요하다면 각각의 타입별로 DoubleBox, BooleanBox와 같이 클래스를 새로 만들어야 함XxxBox 클래스를 생성해야 함Object는 모든 타입의 부모package generic.ex1;
public class ObjectBox {
private Object value;
public void set(Object object) {
this.value = object;
}
public Object get() {
return value;
}
}
Object value를 가지고 있음Object는 모든 타입의 부모ObjectBox에 보관할 수 있음package generic.ex1;
public class BoxMain2 {
public static void main(String[] args) {
ObjectBox integerBox = new ObjectBox();
integerBox.set(10);
Integer integer = (Integer) integerBox.get(); //Object -> Integer 캐스팅
System.out.println("integer = " + integer);
ObjectBox stringBox = new ObjectBox();
stringBox.set("hello");
String str = (String) stringBox.get(); //Object -> String 캐스팅
System.out.println("str = " + str);
//잘못된 타입의 인수 전달시
integerBox.set("문자100");
Integer result = (Integer) integerBox.get(); // String -> Integer 캐스팅 예외
System.out.println("result = " + result);
}
}
integer = 10
str = hello
Exception in thread "main" java.lang.ClassCastException: class java.lang.String
cannot be cast to class java.lang.Integer (java.lang.String and
java.lang.Integer are in module java.base of loader 'bootstrap')
at generic.ex1.BoxMain2.main(BoxMain2.java:24)
integerBox를 만들어서 숫자 10을 보관함integerBox.get()을 호출할 때 문제가 나타남integerBox.get()의 반환 타입은 Object임Object obj = integerBox.get();
Integer = Object는 성립하지 않음(Integer) 타입 캐스팅 코드를 넣어서 Object 타입을 Integer 타입으로 직접 다운 캐스팅해야 함 Integer integer = (Integer) integerBox.get() //1
Integer integer = (Integer) (Object)value //2
Integer integer = (Integer)value //3
StringBox의 경우도 마찬가지임stringBox.get()이 Object를 반환하므로 다음과 같이 다운 캐스팅해야 함 String str = (String) stringBox.get();
integerBox.set("문자100");
integerBox에는 변수 이름과 같이 숫자 타입이 입력되기를 기대함set(Obejct..) 메서드는 모든 타입의 부모인 Object를 매개변수로 받기 때문에 세상의 어떤 데이터도 입력받을 수 있음 Integer result = (Integer) integerBox.get(); //1
Integer result = (Integer) "문자100"; //2
Integer result = (Integer) "문자100"; //3. 예외 발생 String을 Integer로 캐스팅할 수 없다.
String을 Integer로 캐스팅 할 수 없다는 예외가 발생하고 프로그램이 종료됨다형성을 활용한 덕분에 코드의 중복을 제거하고 기존 코드를 재사용할 수 있게 됨
integerBox에는 숫자만 넣어야 하고, stringBox에는 문자열만 입력할 수 있어야 함set()의 매개변수가 Object이기 때문에 다른 타입의 값을 입력할 수 있음반환 시점에도 Object를 반환하기 때문에 원하는 타입을 정확하게 받을 수 없음
결과적으로 이 방식은 타입 안전성이 떨어짐
Object와 다형성을 사용하면 타입 안전성이 떨어지는 문제가 발생함
BoxMain1: 각각의 타입별로IntegerBox,StringBox와 같은 클래스를 모두 정의
- 코드 재사용X
- 타입 안전성O
BoxMain2:ObjectBox를 사용해서 다형성으로 하나의 클래스만 정의
- 코드 재사용O
- 타입 안전성X
💡 제네릭을 사용하면 코드 재사용성과 타입 안전성을 모두 챙길 수 있음