In a nutshell, generics enable types (classes and interfaces) to be parameters when defining classes, interfaces and methods.
Box<T>
는 지네릭 클래스이고, T의 Box, 또는 T Box라고 읽는다. 타입 변수
또는 타입 매개변수
라고 한다. 원시타입
이라고 한다. /**
* 출처 : 독스 튜토리얼 : https://docs.oracle.com/javase/tutorial/java/generics/types.html
* Generic version of the Box class.
* @param <T> the type of the value being boxed
*/
public class Box<T> {
// T stands for "Type"
private T t;
public void set(T t) { this.t = t; }
public T get() { return t; }
}
https://docs.oracle.com/javase/tutorial/java/generics/why.html
List list = new ArrayList();
list.add("hello");
String s = (String) list.get(0);
List<String> list = new ArrayList<String>();
list.add("hello");
String s = list.get(0); // no cast
https://docs.oracle.com/javase/tutorial/java/generics/types.html
public class Box {
private Object object;
public void set(Object object) { this.object = object; }
public Object get() { return object; }
}
/**
* Generic version of the Box class.
* @param <T> the type of the value being boxed
*/
public class Box<T> {
// T stands for "Type"
private T t;
public void set(T t) { this.t = t; }
public T get() { return t; }
}
E - Element (used extensively by the Java Collections Framework)
K - Key
N - Number
T - Type
V - Value
S,U,V etc. - 2nd, 3rd, 4th types
선언할 때는 : 타입 파라미터
실제 사용할 때는 타입 인자라고 한다.
https://docs.oracle.com/javase/tutorial/java/generics/restrictions.html
Pair<int, char> p = new Pair<>(8, 'a'); // compile-time error
Pair<Integer, Character> p = new Pair<>(8, 'a');
Box<Integer> integerBox = new Box<>();
https://docs.oracle.com/javase/tutorial/java/generics/bounded.html
extends
키워드를 사용한다. Box<T>
클래스가 있다고 했을 때,public class NaturalNumber<T extends Integer> {
private T n;
public NaturalNumber(T n) { this.n = n; }
public boolean isEven() {
return n.intValue() % 2 == 0;
}
// ...
}
<T extends B1 & B2 & B3>
Class A { /* ... */ }
interface B { /* ... */ }
interface C { /* ... */ }
class D <T extends A & B & C> { /* ... */ }
public void boxTest(Box<Number> n) { /* ... */ }
Box<Integer>
또는 Box<Double>
가 들어갈 수 있을까? Box<Integer>
과 Box<Double>
은 Box<Number>
의 하위 타입이 아니기 때문이다 .?
은 unknown type을 대표한다. extends
와 super
로 상한과 하한을 제한할 수 있다.
<? extends T>
와일드 카드의 상한 제한. T와 그 자손들만 가능
<? super T>
와일드카드의 하한 제한. T와 그 조상들만 가능
<?>
제한 없음. 모든 타입 가능.<? extends Object>
와 동일
https://docs.oracle.com/javase/tutorial/java/generics/subtyping.html
List<Integer>
와 List<Number>
은 아무런 관계가 아니라고 이야기했다. List<Integer>
는 List<Number>
의 하위 타입이 아니다. List<? extends Integer> intList = new ArrayList<>();
List<? extends Number> numList = intList; // 통과. List<? extends Integer> 는 List<? extends Number>의 서브 타입
https://docs.oracle.com/javase/tutorial/java/generics/methods.html
// 독스 튜토리얼 예시
public 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<Integer, String> p1 = new Pair<>(1, "apple");
Pair<Integer, String> p2 = new Pair<>(2, "pear");
boolean same = Util.<Integer, String>compare(p1, p2);
Pair<Integer, String> p1 = new Pair<>(1, "apple");
Pair<Integer, String> p2 = new Pair<>(2, "pear");
boolean same = Util.compare(p1, p2);
static <T> void sort(List<T> list, Comparator<? super T> c)
https://docs.oracle.com/javase/tutorial/java/generics/rawTypes.html
https://docs.oracle.com/javase/tutorial/java/generics/erasure.html
https://www.baeldung.com/java-type-erasure
public class Node<T> {
private T data;
private Node<T> next;
public Node(T data, Node<T> next) {
this.data = data;
this.next = next;
}
public T getData() { return data; }
// ...
}
public class Node {
private Object data;
private Node next;
public Node(Object data, Node next) {
this.data = data;
this.next = next;
}
public Object getData() { return data; }
// ...
}
public class Node<T extends Comparable<T>> {
private T data;
private Node<T> next;
public Node(T data, Node<T> next) {
this.data = data;
this.next = next;
}
public T getData() { return data; }
// ...
}
public class Node {
private Comparable data;
private Node next;
public Node(Comparable data, Node next) {
this.data = data;
this.next = next;
}
public Comparable getData() { return data; }
// ...
}
public class Node<T> {
public T data;
public Node(T data) { this.data = data; }
public void setData(T data) {
System.out.println("Node.setData");
this.data = data;
}
}
public class MyNode extends Node<Integer> {
public MyNode(Integer data) { super(data); }
public void setData(Integer data) {
System.out.println("MyNode.setData");
super.setData(data);
}
}
MyNode mn = new MyNode(5);
Node n = mn; // A raw type - compiler throws an unchecked warning
n.setData("Hello"); // Causes a ClassCastException to be thrown.
Integer x = mn.data;
Node<Integer>
로 받아야 하지만 raw type으로 받았을 때 타입을 체크할 수 없으니 컴파일은 안나고 노란 밑줄로 unchecked warning을 보여준다. 그렇게 setData에 String 타입을 넣어도 컴파일에는 문제가 없고 실행했을 때 ClassCastException이 발생한다. MyNode mn = new MyNode(5);
Node n = (MyNode)mn; // A raw type - compiler throws an unchecked warning
n.setData("Hello"); // Causes a ClassCastException to be thrown.
Integer x = (String)mn.data;
public class Node {
public Object data;
public Node(Object data) { this.data = data; }
public void setData(Object data) {
System.out.println("Node.setData");
this.data = data;
}
}
public class MyNode extends Node {
public MyNode(Integer data) { super(data); }
public void setData(Integer data) {
System.out.println("MyNode.setData");
super.setData(data);
}
}
MyNode.setData()
가 Node.setData()
를 오버라이드 하지 못한다. (들어오는 인자 타입이 다르므로) class MyNode extends Node {
// Bridge method generated by the compiler
//
public void setData(Object data) {
setData((Integer) data);
}
public void setData(Integer data) {
System.out.println("MyNode.setData");
super.setData(data);
}
// ...
}