For Java generics I have been a little understanding, usually really use not much. It was not until I read Effect Java that I made up my mind that I had to systematically learn and write down many usages that I was not familiar with.

1. Overview of generics

1.1 Origin of generics

As described in Ideas for Java Programming, the motivation for generics is:

There are many reasons for generics, but one of the most notable is the creation of container classes.Copy the code

The idea of generics, such as Templates in C++, is very old. The spirit of templates: Parameterized types

1.2 Basic Overview

  • The nature of generics is “parameterized types”. When it comes to parameters, we are most familiar with the need for parameters when defining methods and for passing arguments when calling methods. Parameterized types are parameterized types that are already concrete
  • The advent of generics eliminates the need for forced conversions, and thus avoids runtime errors when the compiler completes the conversion.

1.3 Purpose of generics

  • Java generics are also syntactic sugar that does the work of converting types at compile time, avoiding classcastExceptions caused by casting types at run time.

1.4 instance

Generics were added in JDK 1.5 to make it much easier to use on collections.

  • Not using generics:
public static void main(String[] args) {
        List list = new ArrayList();
        for(int i = 0; i < list.size(); i++) { System.out.println((String)list.get(i)); }}Copy the code

Because list is Object. So ints and strings can be put in, and they can be taken out. The above code, however, throws a cast exception at runtime, which I’m sure you can understand.

  • Using generics:
public static void main(String[] args) {
        List<String> list = new ArrayList();
        for(int i = 0; i < list.size(); i++) { System.out.println((String)list.get(i)); }}Copy the code

In the example above, we can only add String data, otherwise the compiler will report an error.

2. Use of generics

There are three ways to use generics: generic classes, generic methods, and generic interfaces

2.1 a generic class

  • Generic class Overview: Define generics on classes
  • Definition format:
Public class name < generic type 1,... > {}Copy the code
  • Note: Generic types must be reference types (non-base data types)

2.2 Generic methods

  • Overview of generic methods: Define generics on methods
  • Definition format:
Public < generic type > return type method name (generic type variable name) {}Copy the code
  • Points to note:
    • Parameters defined in a method declaration can be used only in that method, whereas type parameters defined in an interface or class declaration can be used in the entire interface or class. When the fun() method is called, the compiler determines the actual type represented by the type parameter T, based on the actual object passed in.
Class Demo{public <T> T fun(T T){// Can receive any type of datareturnt ; }}; public class GenericsDemo26{ public static void main(String args[]){ Demo d = new Demo() ; String STR = d.fin ("Tom"); // Pass the string int I = d.sun (30); System.out.println(STR); System.out.println(I); // Output content}};Copy the code

2.3 Generic interfaces

  • Generic interface Overview: Define generics in interfaces
  • Definition format:
Public interface Interface name < generic type > {}Copy the code
  • Example:
{} */ public interface Inter<T> {public void show(T T); } public class implements <E> implements <E> {@override public void show(E t) { System.out.println(t); } } Inter<String> inter = new InterImpl<String>() ;"hello");Copy the code

2.4 use of generics in the source code, the following is the List interface and ArrayList class code snippets.

Public interface List<E> extends Collection<E> {public interface List<E> extends Collection<E> { Public E get(int index) {} public void add(E E) {}} Public class ArrayList<E> extends AbstractList<E> implements List<E> {// In this class, E can be used as a type of public voidset(E e) { ....................... }}Copy the code

2.5 Generic Classes Derive subclasses

When a parent class descends a child class, it cannot include a type parameter

  • The wrong way:

public class A extends Container<K, V> {}

  • The right way:

public class A extends Container<Integer, String> {}

  • If you do not specify a specific type, the K and V parameters will be treated as objects

public class A extends Container {}

2.6 Generic constructors

  • A constructor is also a method, hence the so-called generic constructor.
  • There is no difference between using the normal method, one is to display the specified generic parameters and the other is to implicitly infer
public class Person { public <T> Person(T t) { System.out.println(t); }}Copy the code


public static void main(String[] args) { new Person(22); // New <String> Person("hello"); / / show}Copy the code
  • Special note:

    • How to use a generic constructor if the constructor is a generic constructor and the class is also a generic class: Because generic constructors can specify their own type arguments explicitly (diamonds are required, before the constructor) and generic classes need to specify their own type arguments (diamonds are placed after the constructor), there are a few minor problems with having two diamonds at the same time, which are summarized here. Take the following example for example
    public class Person<E> { public <T> Person(T t) { System.out.println(t); }}Copy the code

    Correct usage:

    public static void main(String[] args) {
        Person<String> person = new Person("sss");
    Copy the code

    PS: What does the compiler tell you to do

2.7 Advanced Wildcards

2.7.1 background:

2.7.2 <? Extends T> upper bound wildcard

  • The upper-bound wildcard, as the name implies, <? Extends T> represents an upper bound on a type, so wildmatched parameterized types can be T or subclasses of T.

    • The add method is limited because you can’t determine what type it is (you can add NULL, because NULL represents any type), but you can get an element from the list and assign it to the parent type. As in the first example above, the third add() operation is limited because List and List are List
    It means that all the elements in the collection are Animal or its subclass List<? extends Animal>Copy the code
  • This is known as an upper bound wildcard and is implemented using the extends keyword. When instantiated, the specified type argument can only be a subclass of the extends type or itself.

    • Such as:
    • This way you can determine the type of the element in the set, not the exact type, but at least the parent class. Then do something else.
    //Cat is subclass List<? extends Animal> list = new ArrayList<Cat>();Copy the code

2.7.3 <? Super T> lower bound wildcard

  • The lower wildcard <? Super T> represents a supertype (including itself) of the parameterized type T, all the way up to Object

    • The compiler has no way of determining what type of object get() returns, so the get() method is limited. But can add () method, add () method can add T type and subtype of T type, such as the second example first added a Cat object types, and then add the two subtypes of the Cat object of type, this method is feasible, but if you add a Animal type of object, will clearly opposite the inheritance relationship, Is not feasible.
    It means that all the elements in the collection are Cat or its parent List <, right? super Cat>Copy the code
  • This is known as a lower-bound wildcard and is implemented using the keyword super. When instantiated, the specified type argument can only be a subclass of the extends type or itself

    • For example,
    //Animal is its parent. super Cat> list = new ArrayList<Animal>();Copy the code

2.7.4 <? > unbounded wildcard

  • Any type, if not specified, Object and any Java class
  • Unbounded wildcards are used with
    indicates,? Object is a type, but it does not represent any type. Therefore, List and List have different meaning. The former type is Object, which is the top of the inheritance tree, while the latter type is completely unknown.

Generic erase

3.1 concept

When the compiler compiles a collection with a type specification, the type information is removed

3.2 Verification Example:

public class GenericTest {
    public static void main(String[] args) {
        new GenericTest().testType();

    public void testType(){ ArrayList<Integer> collection1 = new ArrayList<Integer>(); ArrayList<String> collection2= new ArrayList<String>(); System.out.println(collection1.getClass()==collection2.getClass()); System.out.println(collection2.getClass().getName())); // all classes are java.util.ArrayList with no actual type parameter information}}Copy the code
  • Output result:
Copy the code
  • Analysis:
    • This is because no matter which type argument is passed for a generic type parameter, they are still treated as if they were the same class to Java and occupy only one block of memory. From the point of view of the concept of Generics in Java, it is only used at the compile stage of the code. During the compile process, the information about generics is erased after the results of the generics are verified correctly. That is, the class file that has been successfully compiled contains no information about generics. Generic information does not enter the runtime phase.
    • Type parameters are not allowed in the declaration and initialization of static methods, static initializer blocks, or static variables. Since generic classes are not actually generated in the system, they cannot be used after the Instanceof operator

4. Generics and reflection

  • Use the getGenericParameterTypes Method of the Method class to retrieve the actual type parameters of the generic type, using generic variables as Method parameters
  • Example:
public class GenericTest { public static void main(String[] args) throws Exception { getParamType(); } /* Obtain the actual parameter types of Method parameters using reflection */ public static void getParamType() throws NoSuchMethodException{Method Method = GenericTest.class.getMethod("applyMap",Map.class); / / the Type of method for generic parameter Type [] types = method. The getGenericParameterTypes (); System.out.println(types[0]); ParameterizedType pType = (ParameterizedType)types[0]; // The primitive type system.out.println (ptype.getrawType ()); / / the actual type parameters System. Out. Println (pType. GetActualTypeArguments () [0]). System.out.println(pType.getActualTypeArguments()[1]); Public static void applyMap(Map<Integer,String> Map){}}Copy the code
  • Output result:
java.util.Map<java.lang.Integer, java.lang.String>
interface java.util.Map
class java.lang.Integer
class java.lang.String
Copy the code
  • Get around compiler type restrictions on generics by reflection
Public static void main(String[] args) throws Exception {// Define a linked list containing int ArrayList<Integer> al = new ArrayList<Integer>(); al.add(1); al.add(2); Method m = al.getClass().getMethod(); // Add Method to list (); // Add Method to list ();"add", Object.class); // Call reflection's add method to add an element of type string, since the actual argument to add is Object m.invoke(al,"hello");

Copy the code

5 Limitations of generics

5.1 Ambiguity error

  • For the generic class User

    , two generic class parameters are declared. Override the show method in a class for different type arguments.
Public class User<K, V> {public void show(K K) {'show(K)' clashes with 'show(V)'; both methods have same erasure
    public void show(V t) {

Copy the code

Both are essentially Obejct types due to generic erasure. The method is the same, so the compiler will report an error.

Another way:

public class User<K, V> {

    public void show(String k) {

    public void show(V t) {

Copy the code


5.2 Type Parameters cannot be instantiated

The compiler also does not know what type of object to create

public class User<K, V> { private K key = new K(); // Error: Type parameter'K' cannot be instantiated directly

Copy the code

5.3 Restrictions on static Members

Static methods cannot access generics defined on a class; If the type of static method operation is uncertain, generics must be defined on the method.

Static methods must be defined as generic methods if they are to use generics.

Public class User<T> {// error private static T T; // error public static TgetT() {
        returnt; } public static <K> voidtest(K k) {

Copy the code

5.4 Limitations on generic arrays

  • You cannot instantiate an array whose element type is a type parameter, but you can point an array to a reference to a type compatible array
public class User<T> { private T[] values; Public User(T[] values) {this.values = new T[5]; // Correct, values can point to a reference to a type-compatible array this.values = values; }}Copy the code

5.5 Restrictions on generic exceptions

Generic classes cannot extend Throwable, meaning that generic exception class answer links cannot be created