직역하면 ‘일반적인’이란 뜻이다. 즉 데이터 형식에 의존하지않고 하나의 값이 여러개의 타입을 가질수 있도록 하는 방법이다
class CName <T> {
...
}
Interface IName <T> {
...
}
CName<데이터 타입> name = new CName<>();
기본적으로 < >를 하고 그 안에 타입을 넣는다.
여기서 T는 암묵적으로 정한 타입명명규칙이다
타입 | 설명 |
---|---|
Type | |
Element | |
Key | |
Value | |
Number |
Class CName<E> {
private E element;
void set(E element) {
this.element = element;
}
E get() {
return element;
}
}
public class Main {
public static void main(String[] args) {
CName<String> a = new CName<String>();
CName<Integer> b = new CName<Integer>();
a.set("10");
b.set(10);
System.out.println("a data : " + a.get());
System.out.println("b data : " + b.get());
}
}
위처럼 타입 지정을 객체선언때 지정해주고 타입을 String, Integer로 다르게 주었다
그리고 결과를 보면 둘다 정상적으로 출력이 된다
여기서 드는 궁금증은 왜 int, char… 가 아닌 Integer인가다
이유는 제네릭에는 참조타입밖에 오지 못한다.
또한 제네릭은 2개를 선언할수있다
Class CName<K,V> {
private K first;
private V second
void set(K first, V second) {
this.first = first;
this.second = second;
}
K getF() {
return first;
}
V getS() {
return second;
}
}
public class Main {
public static void main(String[] args) {
CName<String, Integer> gTest = new CName<String, Integer>();
gTset.set("10",10);
System.out.println(gTest.getF());
System.out.println(gTest.getS());
}
}
위의 코드와 같은 값인 String, Integer로 선언된 10, 10이 나오게 된다
제네릭은 메소드에서도 쓸수가 있다
public <T> T genericMethod(T t) {
...
}
[접근제어자] <제네릭타입> [리턴타입] [메소드명]([제네릭타입] [파라미터]) {
...
}
제네릭 메소드는 파라미터의 타입에 따라 T가 결정된다
그리고 제네릭 클래스에서 스태틱(static)은 사용이 불가능하다
이유는 스태틱이 붙을경우 프로그램 실행시 바로 메모리에 올라가는데 제네릭은 타입을 지정해주지 않았기때문에 사용할수가 없다.
class ClassName<E> {
static E genericMethod(E o) {
return o;
}
}
class Main {
public static void main(String[] args) {
// ClassName 객체가 생성되기 전에 접근할 수 있으나 타입을 지정할 방법이 없어 에러남
ClassName.getnerMethod(3);
}
}
타입을 지정하지 못하기때문에 위의 코드는 에러가 난다
class ClassName<E> {
private E element; // 제네릭 타입 변수
void set(E element) { // 제네릭 파라미터 메소드
this.element = element;
}
E get() { // 제네릭 타입 반환 메소드
return element;
}
// 아래 메소드의 E타입은 제네릭 클래스의 E타입과 다른 독립적인 타입이다.
static <E> E genericMethod1(E o) { // 제네릭 메소드
return o;
}
static <T> T genericMethod2(T o) { // 제네릭 메소드
return o;
}
}
public class StaticGeneric1 {
public static void main(String[] args) {
ClassName<String> a = new ClassName<String>();
ClassName<Integer> b = new ClassName<Integer>();
a.set("10");
b.set(10);
System.out.println("a data : " + a.get());
System.out.println("b data : " + b.get());
System.out.println();
//제네릭 메소드
System.out.println("<E> returnType : " + ClassName.genericMethod1(3));
System.out.println("<E> returnType : " + ClassName.genericMethod1("ABCD"));
System.out.println("<T> returnType : " + ClassName.genericMethod1(a));
System.out.println("<T> returnType : " + ClassName.genericMethod1(3.0));
}
}
하지만 위의 코드는 가능하다
제네릭 메소드는 제네릭 클래스와 별개로 독립적인 선언이 가능하다
그래서 제네릭클래스의 와 제네릭메소드의는 다른 타입이다
또한 제네릭메소드는 호출시에 타입을 정해주기때문에 스태틱으로 선언이 가능하다
<K extends T> //T와 T의 하위타입만 가능 (K는 들어오는 타입으로 지정됨)
<K super T> //T와 T의 상위타입만 가능 (K는 들어오는 타입으로 지정됨)
<? extends T> //T와 T의 하위타입만 가능
<? super T> //T와 T의 상위타입만 가능
<?> //모든 타입 가능 <? extends Object>랑 같은 의미
쉽게 말해서 알수없는타입(unknown type)이다
이 ?에는 내가 만든클래스타입, Integer, String 등등 범위가 정말 무제한이다
그래서 extends나 super로 상한선 하한선을 정해주어야한다