Параметри на типа в Java Generics
В Java има приети конвенции за именуване на generic параметри. Имената на параметрите на типа са с единични главни букви. Параметрите на генериците се именуват както следва:
| Име | Значение | Къде се ползва |
|---|---|---|
| T | Type | общ тип |
| E | Element | колекции (List, Set и др.) |
| K | Key | ключове в Map |
| V | Value | стойности в Map |
| R | Result | резултати от функции |
| U | Втори свободен тип | когато T вече се използва |
Генериците в Java могат да съдържат повече от един тип параметър. По-долу са дадени най-честите двойки и тяхната роля:
| Параметри | Значение | Къде се ползват |
|---|---|---|
| K, V | Key, Value | Map, HashMap, TreeMap |
| T, U | Два произволни типа | двойки, сравнения, utility класове |
| T, R | Type, Result | функции и трансформации (Function) |
| E, T | Element, Type | колекции, използващи допълнителен тип |
| N, T | Number, Type | numeric utilities, математика |
| T, S | Type, Second type (S = secondary) | generics с два свободни типа |
Разликата между T и U и T и S е само семантична — т.е. свързана е с значението, което програмистът влага, а не с поведение на Java:
- “T” и “U” могат да се зползват, когато имаме два напълно независими, произволни типа. “U” означава втори свободен тип параметър (“U” идва от Unknown, Unused, second type).
- “T” и “S” се използват, когато вторият тип има някаква концептуална връзка с първия. “S” често се чете като „Second Type“, но се използва, когато U не е подходящо, защото искаме да подсетим, че двата типа имат логическа близост.
Raw типове
Raw тип се нарича генеричен клас или интерфейс, при употребата на който не са приложени параметри за тип. Като пример можем да разгледаме генерик класа Box:
public class Box<T> {
public void set(T t) { /* ... */ }
// ...
}
За да бъде създаден параметризиран тип Box, е необходимо като аргумент на формалния параметър T да се добави използвания за казуса тип:
Box<Integer> intBox = new Box<>();
Но ако аргументът, задаващ използвания тип, се пропусне, се създава raw тип на Box:
Box rawBox = new Box();
Следователно Box е raw тип на генеричния тип Box<T>. Трябва да се има предвид обаче, че обикновените класове и интерфейси не са raw тип.
Raw типове се откриват в наследен (legacy) код, тъй като много API класове (като класовете на колекциите ) не са били генерици преди JDK 5.0. Когато използвате raw типове, вие по същество получавате негенерично поведение - Box ви дава Object s. За обратна съвместимост е разрешено присвояването на параметризиран тип към неговия raw тип:
Box<String> stringBox = new Box<>();
Box rawBox = stringBox;
Но ако присвоите необработен тип на параметризиран тип, получавате предупреждение:
Box<String> stringBox = new Box<>();
Box rawBox = stringBox;
rawBox.set(8); // warning: unchecked invocation to set(T)
Предупреждението показва, че необработените типове заобикалят общите проверки за типове, като отлагат улавянето на опасен код за времето за изпълнение. Следователно трябва да избягвате използването на сурови видове.