Appearance
Use generics 
When using ArrayList , if the generic type is not defined, the generic type is actually Object :
java
// compiler warning:
List list = new ArrayList();
list.add("Hello");
list.add("World");
String first = (String) list.get(0);
String second = (String) list.get(1);At this time, <T> can only be used as Object , and the advantages of generics are not used.
When we define the generic type <String> , the generic interface of List<T> becomes the strong type List<String> :
java
// no compiler warnings:
List<String> list = new ArrayList<String>();
list.add("Hello");
list.add("World");
// No forced transformation:
String first = list.get(0);
String second = list.get(1);When we define the generic type <Number> , the generic interface of List<T> becomes the strongly typed List<Number> :
java
List<Number> list = new ArrayList<Number>();
list.add(new Integer(123));
list.add(new Double(12.34));
Number first = list.get(0);
Number second = list.get(1);If the compiler can automatically infer the generic type, it can omit the subsequent generic type. For example, for the following code:
java
List<Number> list = new ArrayList<Number>();When the compiler sees the generic type List<Number> it can automatically infer that the generic type of the following ArrayList<T> must be ArrayList<Number> . Therefore, the code can be abbreviated as:
java
// You can omit the following Number, and the compiler 
// can automatically infer the generic type.:
List<Number> list = new ArrayList<>();Generic interface 
In addition to ArrayList<T> using generics, you can also use generics in interfaces. For example, Arrays.sort(Object[]) can sort any array, but the elements to be sorted must implement Comparable<T> generic interface:
java
public interface Comparable<T> {
    /**
     * Return a negative number: the current instance is smaller than parameter o
     * Return 0: The current instance is equal to parameter o
     * Returns a positive number: the current instance is larger than parameter o
     */
    int compareTo(T o);
}String arrays can be sorted directly:
java
// sort
import java.util.Arrays;
public class Main {
    public static void main(String[] args) {
        String[] ss = new String[] { "Orange", "Apple", "Pear" };
        Arrays.sort(ss);
        System.out.println(Arrays.toString(ss));
    }
}This is because String itself has implemented the Comparable<String> interface. If you try changing to our custom Person type:
java
import java.util.Arrays;
public class Main {
    public static void main(String[] args) {
        Person[] ps = new Person[] {
            new Person("Bob", 61),
            new Person("Alice", 88),
            new Person("Lily", 75),
        };
        Arrays.sort(ps);
        System.out.println(Arrays.toString(ps));
    }
}
class Person {
    String name;
    int score;
    Person(String name, int score) {
        this.name = name;
        this.score = score;
    }
    public String toString() {
        return this.name + "," + this.score;
    }
}When we run the program, we will get ClassCastException , which means that Person cannot be converted to Comparable . We modify the code to let Person implement the Comparable<T> interface:
java
// sort
import java.util.Arrays;
public class Main {
    public static void main(String[] args) {
        Person[] ps = new Person[] {
            new Person("Bob", 61),
            new Person("Alice", 88),
            new Person("Lily", 75),
        };
        Arrays.sort(ps);
        System.out.println(Arrays.toString(ps));
    }
}
class Person implements Comparable<Person> {
    String name;
    int score;
    Person(String name, int score) {
        this.name = name;
        this.score = score;
    }
    public int compareTo(Person other) {
        return this.name.compareTo(other.name);
    }
    public String toString() {
        return this.name + "," + this.score;
    }
}Running the above code can correctly sort by name .
You can also modify the comparison logic, for example, sort by score from high to low. Please modify the test yourself.
Summary 
When using generics, replace the generic parameter <T> with the required class type, for example: ArrayList<String> , ArrayList<Number> etc.;
Types that the compiler can automatically infer can be omitted, for example: List<String> list = new ArrayList<>(); ;
When the generic parameter type is not specified, the compiler will give a warning and can only treat <T> as the Object type;
Generic types can be defined in interfaces, and classes that implement this interface must implement the correct generic type.