" 모든 클래스의 모든 인스턴스는 해당 클래스 유형의 동일한 java.lang.Class 객체를 공유합니다. "
예)
Student a = new Student();
Student b = new Student();
그렇다면 a.getClass() == b.getClass()
사실입니다.
이제 가정
Teacher t = new Teacher();
제네릭이 없으면 아래가 가능합니다.
Class studentClassRef = t.getClass();
그러나 이것은 지금 잘못이다 ..?
예) public void printStudentClassInfo(Class studentClassRef) {}
로 호출 할 수 있습니다Teacher.class
제네릭을 사용하면 피할 수 있습니다.
Class<Student> studentClassRef = t.getClass(); //Compilation error.
이제 T는 무엇입니까 ?? T는 유형 매개 변수 (유형 변수라고도 함)입니다. 꺾쇠 괄호 (<>)로 구분되며 클래스 이름을 따릅니다.
T는 클래스 파일 작성 중에 선언 된 변수 이름 (임의의 이름 일 수 있음)과 같은 기호 일뿐입니다. 나중에
초기화 중에 T가 유효한 클래스 이름 으로 대체됩니다 ( HashMap<String> map = new HashMap<String>();
)
예) class name<T1, T2, ..., Tn>
그래서 Class<T>
특정 클래스 유형 '의 클래스 개체를 나타내는 T
'.
클래스 메소드가 다음과 같이 알 수없는 유형 매개 변수로 작동해야한다고 가정하십시오.
/**
* Generic version of the Car class.
* @param <T> the type of the value
*/
public class Car<T> {
// T stands for "Type"
private T t;
public void set(T t) { this.t = t; }
public T get() { return t; }
}
여기서 T는 CarName 과 같은 String
유형으로 사용할 수 있습니다
OR T는 modelNumberInteger
유형으로 사용할 수 있습니다 .
OR T는 유효한 자동차 인스턴스 로 Object
유형으로 사용될 수 있습니다 .
위의 내용은 런타임에 다르게 사용할 수있는 간단한 POJO입니다.
컬렉션, 예) List, Set, Hashmap은 T 선언에 따라 다른 객체에서 작동하는 가장 좋은 예입니다. 그러나 일단 T를 String으로 선언하면
예를 들어 HashMap<String> map = new HashMap<String>();
String Class 인스턴스 객체 만 허용합니다.
일반적인 방법
일반 메소드는 자체 유형 매개 변수를 도입하는 메소드입니다. 이것은 제네릭 형식을 선언하는 것과 비슷하지만 형식 매개 변수의 범위는 선언 된 메서드로 제한됩니다. 정적 및 비 정적 제네릭 메서드와 제네릭 클래스 생성자가 허용됩니다.
제네릭 메서드의 구문에는 형식 매개 변수, 꺾쇠 괄호가 포함되어 있으며 메서드의 반환 형식 앞에 나타납니다. 일반적인 메서드의 경우 형식 매개 변수 섹션이 메서드의 반환 형식 앞에 나타나야합니다.
class Util {
// Generic static method
public static <K, V, Z, Y> boolean compare(Pair<K, V> p1, Pair<Z, Y> p2) {
return p1.getKey().equals(p2.getKey()) &&
p1.getValue().equals(p2.getValue());
}
}
class Pair<K, V> {
private K key;
private V value;
}
여기 <K, V, Z, Y>
에 반환 유형 앞에 있어야하는 메소드 인수에 사용 된 유형의 선언이 boolean
있습니다.
아래에서; <T>
클래스 수준에서 이미 선언되었으므로 메서드 수준에서는 형식 선언 이 필요하지 않습니다.
class MyClass<T> {
private T myMethod(T a){
return a;
}
}
그러나 클래스 수준 유형 매개 변수 K, V, Z 및 Y를 정적 컨텍스트 (정적 방법)에서 사용할 수 없으므로 아래는 잘못되었습니다.
class Util <K, V, Z, Y>{
// Generic static method
public static boolean compare(Pair<K, V> p1, Pair<Z, Y> p2) {
return p1.getKey().equals(p2.getKey()) &&
p1.getValue().equals(p2.getValue());
}
}
다른 유효한 시나리오는
class MyClass<T> {
//Type declaration <T> already done at class level
private T myMethod(T a){
return a;
}
//<T> is overriding the T declared at Class level;
//So There is no ClassCastException though a is not the type of T declared at MyClass<T>.
private <T> T myMethod1(Object a){
return (T) a;
}
//Runtime ClassCastException will be thrown if a is not the type T (MyClass<T>).
private T myMethod1(Object a){
return (T) a;
}
// No ClassCastException
// MyClass<String> obj= new MyClass<String>();
// obj.myMethod2(Integer.valueOf("1"));
// Since type T is redefined at this method level.
private <T> T myMethod2(T a){
return a;
}
// No ClassCastException for the below
// MyClass<String> o= new MyClass<String>();
// o.myMethod3(Integer.valueOf("1").getClass())
// Since <T> is undefined within this method;
// And MyClass<T> don't have impact here
private <T> T myMethod3(Class a){
return (T) a;
}
// ClassCastException for o.myMethod3(Integer.valueOf("1").getClass())
// Should be o.myMethod3(String.valueOf("1").getClass())
private T myMethod3(Class a){
return (T) a;
}
// Class<T> a :: a is Class object of type T
//<T> is overriding of class level type declaration;
private <T> Class<T> myMethod4(Class<T> a){
return a;
}
}
마지막으로 정적 메소드에는 항상 명시 적 <T>
선언이 필요합니다 . 그것은 수업 수준에서 파생되지 않습니다 Class<T>
. 클래스 수준 T가 인스턴스와 바인딩되어 있기 때문입니다.
또한 읽기 제네릭에 대한 제한을
와일드 카드 및 서브 타이핑
제네릭 메서드의 형식 인수