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
Z dokumentacji Java:
[...] Co bardziej zaskakujące, klasa Klasa została wygenerowana. Literały klasowe działają teraz jako tokeny typów, zapewniając informacje zarówno o czasie wykonywania, jak i o czasie kompilacji. Umożliwia to styl statycznych fabryk, których przykładem jest metoda getAnnotation w nowym interfejsie AnnotatedElement:
To jest ogólna metoda. Pobiera wartość swojego parametru typu T z argumentu i zwraca odpowiednią instancję T, co ilustruje poniższy fragment:
Przed lekami generycznymi musiałbyś przekazać wynik autorowi. Nie miałbyś także sposobu, aby kompilator sprawdził, czy rzeczywisty parametr reprezentuje podklasę Adnotacji. [...]
Cóż, nigdy nie musiałem używać tego rodzaju rzeczy. Ktoś?
źródło
Class<? extends X>
notacji, pomyślałem, że mogę ograniczyć ją tylko do typów „usługowych”. Tyle że nie było powszechnego rodzaju „usługi”, więc mogłem to zrobić tylko zClass<?>
. Niestety.Znalazłem
class<T>
przydatna, gdy tworzę wyszukiwań rejestru usług. Na przykładźródło
Jak wskazują inne odpowiedzi, istnieje wiele dobrych powodów, aby
class
uczynić to ogólnym. Jednak jest wiele razy, że nie masz możliwości poznania ogólnego typu, z którym chcesz korzystaćClass<T>
. W takich przypadkach możesz po prostu zignorować żółte ostrzeżenia zaćmienia lub użyćClass<?>
... Tak to robię;)źródło
@SuppressWarnings("unchecked")
przychodzi na ratunek! (Wystarczy być ostrożnym, aby zawsze stosować go jako małego zakresu, jak to możliwe, jak to robi niejasnych problemów potencjał w kodzie.)Idąc za odpowiedzią @Kire Haglin, kolejny przykład metod ogólnych można znaleźć w dokumentacji dotyczącej rozłączania JAXB :
Umożliwia
unmarshal
to zwrócenie dokumentu dowolnego typu drzewa zawartości JAXB.źródło
Często chcesz używać symboli wieloznacznych
Class
. Na przykład,Class<? extends JComponent>
pozwoli ci określić, że klasa jest jakąś podklasąJComponent
. Jeśli odzyskałeśClass
instancjęClass.forName
, możesz użyćClass.asSubclass
rzutowania przed próbą, na przykład, skonstruowania instancji.źródło
W języku Java
<T>
oznacza klasę ogólną. Klasa ogólna to klasa, która może pracować z dowolnym typem danych lub innymi słowy możemy powiedzieć, że jest niezależna od typu danych.Gdzie T oznacza typ. Teraz, gdy utworzysz instancję tej klasy Shape, będziesz musiał poinformować kompilator o typie danych, nad którym będzie pracował.
Przykład:
Liczba całkowita jest typem, a ciąg znaków jest również typem.
<T>
w szczególności oznacza rodzaj ogólny. Według Java Docs - Typ ogólny to ogólna klasa lub interfejs, który jest parametryzowany względem typów.źródło
Aby rzucić inny przykład, ogólna wersja Class (
Class<T>
) pozwala pisać ogólne funkcje, takie jak ta poniżej.źródło
Na początku jest to mylące. Ale pomaga to w poniższych sytuacjach:
źródło
Action a = new Action()
?Action
w interfejsie,SomeAction
próbujemy uzyskać instancję. Mamy tylko nazwęSomeAction
dostępną w czasie wykonywania.Wystarczy użyć klasy wołowiny:
źródło