Generics

Concept:
Generics make an object that uses a certain class, enforce that only the (sub)class(es) of a particular type can go into a certain object / method. text

Rationale:
In the past developer used to work with objects in which Objects go in, and were casted to the right type to enable use of a particular class' methods. This made the object being used very prone to ClassCastExceptions. With Generics, the compiler forces that only objects of the defined type can be used with a certain object.

Type erasure:
Behind the scenes the compiler changes the Generic Symbols used, like T/K/V to Objects and adds the relevant casts for the code to work with the type of the erased class.

Generic Classes

Generic methods

Defined on
class level

Example:
Public class SomeGenericClass<T> {}


SomeGenericClass<String> s = new SomeGenericClass<>();

Bounds

Example with return type:


public <T> SomeRandomGenericClass<T> doSomething(T t) {
System.out.println("You put in a" + t);
return new SomeRandomGenericClass<T>;
}

Example without return type:
public <T> void doSomethingElse(T t) {
System.out.println("Here's a " + t);
}

Concept:
Generic objects generally are treated like 'Object' class due to the type erasure, to solve this, bounds have been introduced

Upper bounded wildcard

unbounded wildcard

Lower bounded wildcard

Use:
Specifies that any type that is a superclass of ? can be used in the generic. All objects being passed to the generic are treated like a superclass of ?.

Use:
Specifies that any type is okay. Generic types using this wildcard are treated like a class from 'Object'

Syntax:
List<?> list = new ArrayList<>();

Use:
Specifies that any type that extends ? can be used in the generic. Note that using upper bound generics, make them immutable by default.

Syntax:
List<? super Number> list = new ArrayList<>();

Syntax:
List<? extend Number> list = new ArrayList<>();