Ethickfox kb page with all notes
Special Java language tools for implementing generalized programming: a specific approach to describing data and algorithms, allowing you to work with different types of data without changing their description. Generic type parameter is when a type can be used as a parameter in a class, method or interface declaration.
It’s important to realise that generic type information is only available to the compiler, not the JVM. In other words**,** type erasure means that generic type information is not available to the JVM at runtime, only compile time. Types can be divided into:
<?>, ArrayList<?>, or Map<?, ?>)int[], Number[], List<?>[], List[], or int[][]) List<String>[] and Heap polution would occur.
List<Number>, ArrayList<String>, or Map<String, Integer>)List<? extends Number> or Comparable<? super String>)The reasoning behind major implementation choice is simple – preserving backward compatibility with older versions of Java. When a generic code is compiled into bytecode, it will be as if the generic type never existed. This means that the compilation will:
| T (Тип) | |T| (Затирание типа) |
List<Integer>, List< String>, List< List< String>> |
List |
List<Integer>[] |
List[] |
| List | List |
| int | int |
| Integer | Integer |
<T extends Comparable<T>> |
Comparable |
<T extends Object & Comparable<? super T>> |
Object |
LinkedCollection<E>.Node |
LinkedCollection.Node |
| Bridge методы | |
| Создадим класс с наследованием от дженерика |
public class ErasureTest implements Comparable<ErasureTest> {
@Override
public int compareTo(ErasureTest o) {
return 0;
}
public int compareTo(Object o) {
return 0;
}
}
Возникает compile-time error создается метод compareTo(Object o), а он уже есть. Оба метода останутся
There is one situation where a generic type is available at runtime. This is when a generic type is part of the class signature like so:
public class CatCage implements Cage<Cat>
(Class<T>)((ParameterizedType)getClass().getGenericSuperclass()).getActualTypeArguments()[0];
Implementation of polymorphism for generics. Because if B is the successor of A, Collection<B> is not the successor of Collection<A>. Collection<?> Can accept any of the types. A wildcard type represents an unknown type.
An upper bounded wildcard is when a wildcard type inherits from a concrete type. Wildcard with the specified upper border (List<? extends Number>) Allows you to read from the structure:
void printListSum(List<? extends Number> list) {
for (Number number : list)
System.out.println(number.intValue());
}
printListSum(new ArrayList<Integer>());
printListSum(new ArrayList<Double>());
printListSum(new ArrayList<String>()); // --
printListSum(new ArrayList<Object>()); // --
printListSum(new ArrayList<ArrayList<String>>()); // --

Wildcard с указанной верхней границей (List<? extends Number>) Позволяет читать из структуры:
void printListSum(List<? extends Number> list) {
for (Number number : list) {
System.out.println(number.intValue());
}
}
printListSum(new ArrayList<Integer>());
printListSum(new ArrayList<Double>());
printListSum(new ArrayList<String>()); // --printListSum(new ArrayList<Object>()); // --
printListSum(new ArrayList<ArrayList<String>>()); // --
Lower bounded wildcard means we are forcing the type to be a superclass of our bounded type.Wildcard with the specified lower border (List<? supper Number>) Allows you to write in structures:
void insertNumbers(List<? super Number> list){
for (int i = 0; i < 10; i++) {
list.add(i);
list.add("test"); // error
}
}
insertNumbers(new ArrayList<String>()); // --
insertNumbers(new ArrayList<Double>()); // --
insertNumbers(new ArrayList<Number>());
insertNumbers(new ArrayList<Object>());

When we use bounded parameters, we are restricting the types that can be used as generic type arguments. As an example, let’s say we want to force our generic type always to be a subclass of animal:
public abstract class Cage<T extends Animal> {
abstract void addAnimal(T animal)
}
An unbounded wildcard is a wildcard with no upper or lower bound, that can represent any type. It is not the same as the Object, because there is no inheritance for generics
List<?> wildcardList = new ArrayList<String>();
List<Object> objectList = new ArrayList<String>(); // Compilation error
public abstract class Cage<T extends Animal & Comparable>
It’s also worth remembering that if one of the upper bounds is a class, it must be the first argument.
Multiple restrictions. It is written via the character "&", that is, we say that the type represented by a variable of type T must be bounded at the top by the Object class and the Comparable interface.
<T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll)
Covariance - List can be assigned to a variable of type List (as if it is a successor of List). Arrays are covariant: Object[] can be set to String[].
List<Integer> можно присвоить в переменную типа List<? extends Number> (как будто он наследник List<Number>). Массивы ковариантны: в переменную Object[] можно присвоить значение типа String[].
Object[] strings = new Object[5];
strings = new String[3];
Contravariance - As a parameter of List<Number>.#sort of Comparator<? super Number> can be passed to Comparator<Object> (as if it were the parent of Comparator)
В качестве параметра метода List<Number>\#sort типа Comparator<? super Number> может быть передан Comparator<Object> (как будто он родитель Comparator<Number>)
Invariance - Lack of covariance and counter-variant properties. Generics without wildcards are invariant: List cannot be placed in a List or List variable.
Отсутствие свойств ковариантности и контрвариантности. Дженерики без вайлдкардов инвариантны: List<Number> нельзя положить ни в переменную типа List<Double>, ни в List<Object>.
Type inference is when the compiler can look at the type of a method argument to infer a generic type. For example, if we passed in T to a method which returns T, then the compiler can figure out the return type.
Integer inferredInteger = returnType(1);
String inferredString = returnType("String");
public static void reverse(List<?> list) {
List<Object> tmp = new ArrayList<Object>(list);
for (int i = 0; i < list.size(); i++) {
list.set(i, tmp.get(list.size()-i-1)); // compile-time error
}
}
Ошибка компиляции возникла, потому что в методе reverse в качестве аргумента принимается список с неограниченным символом подстановки <?> .
<?>означает то же что и <? extends Object>. Следовательно, согласно принципу PECS, list – это producer. А producer только продюсирует элементы. А мы в цикле for вызываем метод set(), т.е. пытаемся записать в list. И поэтому упираемся в защиту Java, что не позволяет установить какое-то значение по индексу.
Нам поможет паттерн Wildcard Capture. Здесь мы создаем обобщенный метод rev. Он объявлен с переменной типа T. Этот метод принимает список типов T, и мы можем сделать сет.
public static void reverse(List<?> list) {
rev(list);
}
private static <T> void rev(List<T> list) {
List<T> tmp = new ArrayList<T>(list);
for (int i = 0; i < list.size(); i++) {
list.set(i, tmp.get(list.size()-i-1));
}
}
The situation that occurs when a parameterized variable of type points to an object that is not of this parameterized type. So the data in the pile isn’t the type we’re expecting.
List<A> listOfAs = new ArrayList<>();
List<B> listOfBs = (List<B>)(Object)listOfAs; //points to a list of As
Heap pollution может произойти в двух случаях: при использовании массивов дженериков и при смешивании параметризованных и raw-типов.
Может привести к ClassCastExceptions или ArrayStoreException, поэтому во время компиляции будет выдано предупреждение. Можно сапресить через @SaveVarargs. https://habr.com/ru/post/207360
Added in Java 16 Реализован через обновленный instanceof
// Old
if(obj instanceof String) {
String str = (String) obj;
System.out.println(str.toLowerCase());
}
// New
if (obj instanceof String str) {
System.out.println(str.toLowerCase());
}