728x90
반응형
Generics
제네릭의 사용 이유
컴파일 시간 단축
캐스트의 제거
Generics class, interface
// raw type Box class
public class Box {
private Object object;
public void set(Object object) { this.object = object; }
public Object get() { return object; }
}
// generic type Box class
public class Box<T> {
private T t;
public void set(T t) { this.t = t; }
public T get() { return t; }
}
클래스 또는 인터페이스의 이름 뒤에 <>를 통해 타입 매개변수를 지정할 수 있음
타입 매개변수 예시
E - Element
K - Key
N - Number
T - Type
V - Value
예시 1
class Box<T> {
private T t;
public T get() { return t; }
public void set(T t) { this.t = t; }
}
public class Main {
public static void main(String[] args) {
Box<String> box1 = new Box<String>();
box1.set("hello");
String str = box1.get();
Box<Integer> box2 = new Box<>(); // type inference
box2.set(6); // 객체 생성시 타입 매개변수 생략 가능
int value = box2.get();
}
}
예시 2
class Box<T> { private T t;
public T get() { return t; }
public void set(T t) { this.t = t; }
}
interface Pair<K, V> {
public K getKey();
public V getValue();
}
class OrderedPair<K, V> implements Pair<K, V> {
private K key; private V value;
public OrderedPair(K key, V value) {
this.key = key;
this.value = value;
}
public K getKey(){ return key; }
public V getValue() { return value; }
}
public class Main {
public static void main(String[] args) {
Pair<String, Integer> p1 = new OrderedPair<String, Integer>("Even", 8);
Pair<String, String> p2 = new OrderedPair<String, String>("hello", "world");
OrderedPair<String, Integer> p3 = new OrderedPair<>("Even", 8);
OrderedPair<String, String> p4 = new OrderedPair<>("hello", "world");
OrderedPair<String, Box<Integer>> p = new OrderedPair<>("primes", new Box<Integer>());
// new OrderedPair<>("primes", new Box<>()); 가능
}
}
Generics method
<T, R> R method(T t)
ststic <T> void method(T t)
<R> R method(int arg)
위와 같은 형태로 표현
예시 1
class Box<T> {
private T t;
public <T> T method1(T t) { return this.t = t; }
// 제네릭 메소드(O), 메소드의 타입 매개변수 T와 클래스의 T(this.t의 타입)는 다름, 컴파일 에러
public T method2(T t) { return this.t = t; }
// 제네릭 메소드(X)
}
class Box {
static <T> void method(T t) {...}
// 제네릭 메소드 (O)
}
예시 2
class Util {
public static <K, V> boolean compare(Pair<K, V> p1, Pair<K, V> p2) {
return p1.getKey().equals(p2.getKey()) &&
p1.getValue().equals(p2.getValue());
}
/* 주석처리된 메소드에 비해 위쪽 제네릭을 사용한 메소드는 다양한 형태의 Pair를 사용할 수 있음
public static boolean compare(Pair<Integer, String> p1, Pair<Integer, String> p2) {
return p1.getKey().equals(p2.getKey()) &&
p1.getValue().equals(p2.getValue());
}
*/
}
class Pair<K, V> {
private K key;
private V value;
public Pair(K key, V value) {
this.key = key;
this.value = value;
}
public void setKey(K key) { this.key = key; }
public void setValue(V value) { this.value = value; }
public K getKey() { return key; }
public V getValue() { return value; }
}
public class Main {
public static void main(String[] args) {
Pair<Integer, String> p1 = new Pair<>(1, "apple");
Pair<Integer, String> p2 = new Pair<>(2, "pear");
boolean same1 = Util.<Integer, String>compare(p1, p2);
boolean same2 = Util.compare(p1, p2); // type inference
// 컴파일러가 메소드의 타입 매개변수 형을 추론 가능한 경우
// 타입 매개변수 형을 명시하지 않아도 됨
// 대부분의 경우 이렇게 사용
}
}
Bounded Type parameters
타입 매개변수의 형태를 한정할 수 있음
<U extends Number>
Number를 포함해서 Number를 상속받는 클래스로 U의 범위를 제한
또한 U는 Number를 상속받는 클래스이므로 U.intValue()와 같은 Number의 메소드 사용 가능
(<T>의 경우, 기본적으로 Object를 상속받아 Object의 메소드 사용 가능)
인터페이스와 클래스로 타입 매개변수 형태 한정
class A { /* ... */ }
interface B { /* ... */ }
interface C { /* ... */ }
// 클래스는 상속이 하나만 가능하므로, 클래스 인터페이스의 순서를 맞춰주어야 함
// class Box extends A implements B, C {}
class D <T extends A & B & C> { /* ... */ }
class D <T extends B & A & C> { /* ... */ } // compile-time error
상속과 매개변수 형태 한정
public void boxTest(Box<Number> n) { /* ... */ }
boxTest(new Box<Integer>) // 오류
// Number과 Integer는 상속관계지만
// Box<Number>와 Box<Integer>는 상속 관계가 아님
// 이를 해결하기 위해 와일드카드<?> 개념 도입
Wildcards <?>
List<?> ln = new LinkedList<Number>();
List<?> li = new LinkedList<Integer>();
// 지역변수 선언, 필드 선언, 매개변수 선언에 활용 가능
와일드 카드와 서브타입
Upper Bounded Wildcards
public class Main {
public static double sumOfList(List<? extends Number> list) {
double s = 0.0;
for (Number n : list)
s += n.doubleValue();
return s;
}
public static void main(String[] args) {
List<Integer> li = Arrays.asList(1, 2, 3);
System.out.println("sum = " + sumOfList(li));
List<Double> ld = Arrays.asList(1.2, 2.3, 3.5);
System.out.println("sum = " + sumOfList(ld));
}
}
Lower Bounded Wildcards
public static void addNumbers (List < ? super Integer > list)
{
for (int i = 1; i <= 10; i++) {
list.add(i);
}
}
Unbounded Wildcards
public class Main {
public static void printList(List<?> list) {
for (Object elem: list)
System.out.print(elem + " "); System.out.println();
}
public static void main(String[] args) {
List<Integer> li = Arrays.asList(1, 2, 3);
List<String> ls = Arrays.asList("one", "two", "three");
printList(li);
printList(ls);
}
}
728x90
반응형
'전공 > 객체지향프로그래밍' 카테고리의 다른 글
[객체지향프로그래밍][Java] Object Cloning (0) | 2023.06.07 |
---|---|
[객체지향프로그래밍][Java] Initialization (정적 초기화 블록, 인스턴스 초기화 블록) (0) | 2023.06.07 |
[객체지향프로그래밍][Java] Queue 심화 내용 (0) | 2023.06.01 |
[객체지향프로그래밍][Java] Set 심화 내용(HashSet, TreeSet) (0) | 2023.06.01 |
[객체지향프로그래밍][Java] List 심화 내용(Iterator) (0) | 2023.06.01 |