Typ ogólny to klasa ogólna lub interfejs, który jest sparametryzowany względem typów. Następująca klasa Box zostanie zmodyfikowana, aby zademonstrować tę koncepcję.
Prosta klasa Box
Rozpocznij od zbadania nieogólnej klasy Box, która działa na obiektach dowolnego typu. Musi tylko dostarczyć dwie metody: set, która dodaje obiekt do pudełka i get, która go pobiera:
Ponieważ jego metody akceptują lub zwracają obiekt, możesz swobodnie przekazać cokolwiek chcesz , pod warunkiem, że nie jest to jeden z typów pierwotnych. Nie ma możliwości sprawdzenia, w czasie kompilacji, jak ta klasa jest używana. Jedna część kodu może umieścić w polu liczbę całkowitą i oczekiwać, że z niej wyjdą liczby całkowite, podczas gdy inna część kodu może omyłkowo przekazać ciąg znaków, powodując błąd w czasie wykonywania.
Wersja ogólna klasy Box
Klasa ogólna ma następujący format:
class name<T1, T2, ..., Tn> { /* ... */ }
Aby zaktualizować Box, aby używać typów ogólnych, tworzysz deklarację typu ogólnego, zmieniając kod „public class Box” na „public class Box < T > ”. Wprowadza to zmienną typu T, której można użyć w dowolnym miejscu w klasie.
Po tej zmianie klasa Box staje się:
Jak widać, wszystkie wystąpienia Object są zastąpiona przez T. Zmienna typu może być dowolnym innym niż pierwotnym typem, który podasz: dowolnym typem klasy, dowolnym typem interfejsu, dowolnym typem tablicy lub nawet innym typem.
Tę samą technikę można zastosować do tworzenia ogólne interfejsy.
Konwencje nazewnictwa parametrów typu
Zgodnie z konwencją, nazwy parametrów typów są pojedynczymi dużymi literami. Kontrastuje to ostro z konwencjami nazewnictwa zmiennych, o których już wiesz, i nie bez powodu: bez tej konwencji trudno byłoby odróżnić zmienną typu od zwykłej nazwy klasy lub interfejsu.
Najczęściej używanymi nazwami parametrów typu są:
- E – Element (szeroko używane w środowisku Java Collections Framework)
- K – Key
- N – liczba
- T – typ
- V – wartość
- S, U, V itd. – 2, 3, 4 typy
Nazwy te będą używane w całym API Java SE i w pozostałej części tej lekcji.
Wywoływanie i tworzenie instancji typu ogólnego
Aby odwołać się do ogólnej klasy Box z poziomu kodu należy wykonać wywołanie typu ogólnego, które zastępuje T pewną konkretną wartością, taką jak Integer:
Box<Integer> integerBox;
Możesz myśleć o wywołaniu typu ogólnego jak o wywołaniu zwykłej metody, ale zamiast przekazywania argumentu do am ethod, przekazujesz argument typu – w tym przypadku Integer – do samej klasy Box.
Jak każda inna deklaracja zmiennej, ten kod w rzeczywistości nie tworzy nowego obiektu Box. Po prostu deklaruje, że integerBox będzie zawierał odniesienie do „Box of Integer”, czyli w ten sposób odczytywany jest Box < Integer >.
Wywołanie typu ogólnego jest ogólnie znane jako typ sparametryzowany.
Aby utworzyć instancję tej klasy, jak zwykle użyj słowa kluczowego new, ale umieść < Integer > między nazwą klasy a nawiasem:
Box<Integer> integerBox = new Box<Integer>();
Diament
W języku Java SE 7 i nowszych można zastąpić argumenty typu wymagane do wywołania konstruktora klasy ogólnej pustym zestawem argumentów typu (< >), o ile kompilator może określić lub wywnioskować argumenty typu z kontekstu. Ta para nawiasów kątowych, < >, jest nieformalnie nazywana diamentem. Na przykład możesz utworzyć wystąpienie Box < Integer > za pomocą następującej instrukcji:
Box<Integer> integerBox = new Box<>();
Aby uzyskać więcej informacji na temat notacji rombu i wnioskowania o typie, zobacz Wnioskowanie o typie.
Wiele parametrów typu
Jak wspomniano wcześniej, klasa ogólna może mieć wiele parametrów typu.Na przykład ogólna klasa OrderedPair, która implementuje ogólny interfejs Pair:
Poniższe instrukcje tworzą dwie instancje klasy OrderedPair:
Kod, nowy OrderedPair < String, Integer >, tworzy instancję K jako ciąg i V jako liczbę całkowitą. Dlatego typami parametrów konstruktora OrderedPair są odpowiednio String i Integer. Ze względu na autoboxing prawidłowe jest przekazywanie String i int do klasy.
Jak wspomniano w The Diamond, ponieważ Kompilator Java może wywnioskować typy K i V na podstawie deklaracji OrderedPair < String, Integer >, te instrukcje można skrócić za pomocą notacji diamentowej:
OrderedPair<String, Integer> p1 = new OrderedPair<>("Even", 8);OrderedPair<String, String> p2 = new OrderedPair<>("hello", "world");
Aby utworzyć interfejs ogólny, postępuj zgodnie z tymi samymi konwencjami, co przy tworzeniu klasy ogólnej.
Typy sparametryzowane
OrderedPair<String, Box<Integer>> p = new OrderedPair<>("primes", new Box<Integer>(...));