Wiemy tylko: „ Wszystkie wystąpienia dowolnej klasy współużytkują ten sam obiekt java.lang.Class tego typu klasy ”
na przykład)
Student a = new Student();
Student b = new Student();
To a.getClass() == b.getClass()
jest prawda.
Załóżmy teraz
Teacher t = new Teacher();
bez leków generycznych możliwe jest poniżej.
Class studentClassRef = t.getClass();
Ale teraz to źle…
np.) public void printStudentClassInfo(Class studentClassRef) {}
można wywołać za pomocąTeacher.class
Można tego uniknąć za pomocą ogólnych.
Class<Student> studentClassRef = t.getClass(); //Compilation error.
Co to jest T ?? T to parametry typu (zwane również zmiennymi typu); rozdzielone nawiasami kątowymi (<>), następuje po nazwie klasy.
T jest tylko symbolem, podobnie jak nazwa zmiennej (może być dowolną nazwą) zadeklarowana podczas pisania pliku klasy. Później T zostanie zastąpione
prawidłową nazwą klasy podczas inicjalizacji ( HashMap<String> map = new HashMap<String>();
)
na przykład) class name<T1, T2, ..., Tn>
Zatem Class<T>
reprezentuje obiekt klasy określonego typu klasy „ T
”.
Załóżmy, że metody klas muszą działać z nieznanymi parametrami typu, jak poniżej
/**
* 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; }
}
Tutaj T może być użyty jako String
typ CarName
LUB T może być użyte jako Integer
typ jako modelNumber ,
LUB T może być użyte jako Object
typ jako poprawna instancja samochodu .
Teraz tutaj powyższe jest prostym POJO, którego można używać inaczej w czasie wykonywania.
Kolekcje np. List, Set, Hashmap są najlepszymi przykładami, które będą działać z różnymi obiektami zgodnie z deklaracją T, ale kiedy zadeklarujemy T jako String
np.) HashMap<String> map = new HashMap<String>();
Wtedy zaakceptuje tylko obiekty instancji klasy String.
Metody ogólne
Metody ogólne to metody, które wprowadzają własne parametry typu. Jest to podobne do deklarowania typu ogólnego, ale zakres parametru typu jest ograniczony do metody, w której jest zadeklarowany. Dozwolone są statyczne i niestatyczne metody ogólne, a także konstruktory klas ogólnych.
Składnia metody ogólnej zawiera parametr typu, wewnątrz nawiasów kątowych i pojawia się przed typem zwracanym przez metodę. W przypadku metod ogólnych sekcja parametru typu musi pojawić się przed typem zwracanym przez metodę.
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;
}
Oto <K, V, Z, Y>
deklaracja typów użytych w argumentach metody, które powinny występować przed typem zwracanym, który jest boolean
tutaj.
Poniżej; deklaracja typu <T>
nie jest wymagana na poziomie metody, ponieważ jest już zadeklarowana na poziomie klasy.
class MyClass<T> {
private T myMethod(T a){
return a;
}
}
Ale poniżej jest źle, ponieważ parametry typu K, V, Z i Y na poziomie klasy nie mogą być używane w kontekście statycznym (tutaj metoda statyczna).
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());
}
}
POZOSTAŁY INNE WAŻNE SCENARIUSZE
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;
}
}
I wreszcie metoda statyczna zawsze wymaga wyraźnej <T>
deklaracji; Nie będzie pochodzić z poziomu klasy Class<T>
. Wynika to z faktu, że poziom klasy T jest związany z instancją.
Przeczytaj także Ograniczenia dotyczące leków generycznych
Symbole wieloznaczne i subtyping
Argument typu dla metody ogólnej