An overview,

Java Generics is a new feature introduced in JDK 1.5. Generics provide compile-time type-safety checks that allow developers to detect illegal types at compile time.

1.1 What are Generics?

  • Generics, parameterized types.

When it comes to parameters, you’re most familiar with defining tangible arguments to a method and then passing the arguments when the method is called. So what about parameterized types? As the name implies, a type is parameterized from an original concrete type, similar to a variable parameter in a method. In this case, the type is also defined as a parameter (called a type parameter), and then passed in the concrete type (type argument) when the/is used.

  • The nature of generics is to parameterize types

Controls the types of parameters that are specifically restricted by the different types specified by the generic without creating new types. That is, in the use of generics, the data type of the operation is specified as a parameter, which can be used in classes, interfaces, and methods, called generic classes, generic interfaces, and generic methods, respectively.

1.2 For example:

@Test
public void genericDemo(a) {
    List list = new ArrayList();
    list.add("The Dust Blog");
    list.add(100);

    for(int i = 0; i< list.size(); i++){ String item = (String)list.get(i); log.info("item:{}", item); }}Copy the code

The program will no doubt end in a crash:

java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
Copy the code

An ArrayList can hold any type. In this example, we added a String and then an Integer. When used, they are used as strings, so the program crashes. Generics were created to solve problems like this, which can be solved at compile time.

1.3 features

Generics are only valid at compile time

  1. Type safety is checked at compile time, and all casts are automatic and implicit;
  2. Logically seen as multiple different types, they are actually the same basic type.

The use of generics

Generics can be used in three ways: generic classes, generic interfaces, and generic methods.

2.1 a generic class

Generic types are used in the definition of classes and are called generic classes. Generics make it possible to open the same interface to operations on a set of classes. The most typical are the various container classes: List, Set, Map.

2.1.1 A most common generic class:

public class Generic<T> {
    /** * key This member variable is of type T, which is externally specified */
    private T key;

    /** * The generic constructor parameter key is also of type T, whose type is externally specified *@param key
     */
    public Generic(T key) {
        this.key = key;
    }

    /** * The generic method getKey() returns a value of type T, whose type is externally specified *@return* /
    public T getKey(a){
        returnkey; }}Copy the code

Description:

  1. hereTCan be written as any identifier, common asT,E,K,VArguments of the same form are often used to represent generics;
  2. Must be specified when instantiating a generic classTThe specific type of.

2.1.2 The use of generics

  • Specify generic types
@Test
public void genericDemoWithType(a) {
    // The type parameter of a generic type can only be a class type (including a custom class), not a simple type
    Generic<Integer> integerGeneric = new Generic<Integer>(123456);
    log.info("integerGeneric key is:{}", integerGeneric.getKey());

    // The argument type passed in must be of the same type as the generic type parameter, that is, String.
    Generic<String> stringGeneric = new Generic<String>("The Dust Blog");
    log.info("stringGeneric key is:{}", stringGeneric.getKey());
}
Copy the code
  • Generic types are not specified

A method or member variable defined using a generic type in a generic class can be of any type, provided that no generic type argument is passed.

@Test
public void genericDemoWithOutType(a) {
    Generic generic = new Generic("111111");
    Generic generic1 = new Generic(4444);
    Generic generic2 = new Generic(55.55);
    Generic generic3 = new Generic(false);
    log.info("generic key is:{}",generic.getKey());
    log.info("generic1 key is:{}",generic1.getKey());
    log.info("generic2 key is:{}",generic2.getKey());
    log.info("generic3 key is:{}",generic3.getKey());
}
Copy the code

Print the result

. generic key is:111111 ... generic1 key is:4444 ... Generic2 key is: 55.55... generic3 key is:falseCopy the code

2.1.3 Summary of generic classes

  1. The type parameters of a generic type can only be class types, not simple types;
  2. Cannot be used for exact generic typesinstanceofOperation.

2.2 Generic interfaces

Generic interfaces are defined and used in much the same way as generic classes. Generic interfaces are often used in producers of various classes, such as:

public interface Generator<T> {
    public T next(a);
}
Copy the code
  • When a class that implements a generic interface passes no generic arguments

If no generic argument is passed, the same as the definition of the generic class, the declaration of the generic type must be added to the class when the class is declared.

public class FruitGenerator<T> implements Generator<T>{

    public T next(a) {
        return null; }}Copy the code
  • When implementing a generic interface class, the generic argument is passed

When an implementation class implements a generic interface, if a generic type is passed in as an argument type, all uses of the generic type are replaced with the argument type passed in.

public class VegetablesGenerator implements Generator<String>{

    private String[] vegetables = new String[]{"Potato"."Tomato"};

    public String next(a) {
        Random rand = new Random();
        return vegetables[rand.nextInt(2)]; }}Copy the code

This section provides an example code address

2.3 Generic methods

In Java, the definition of generic classes is very simple, but generic methods are more complex.

Most of the member methods we see in generic classes also use generics, and some even have generic methods in them.

  • The difference between generic classes and generic methods
The name of the A generic class Generic method
The difference between Specify the specific type of the generic when instantiating the class The specific type of the generic is specified when the method is called

2.3.1 definition

public <T> T showKeyName(GenericMethodDemo<T> container){    
    return null;
}
Copy the code
  1. First of all inpublicAnd the return value<T>Essential, which indicates that this is a generic method and declares a genericT;
  2. thisTCan appear anywhere in the generic method;
  3. The number of generics can be as many as you want.
public class GenericMethodDemo {

    /** * generic class *@param <T>
     */
    public class Generic<T> {
        private T key;

        public Generic(T key) {
            this.key = key;
        }

        /** * this is not a generic method, * this is a normal member of the class, but its return value is declared in the generic class already declared by the generic class, * so we can continue to use T in this method. *@return* /
        public T getKey(a) {
            return key;
        }

        /** * This is a true generic method *@param container
         * @param <T>
         * @return* /
        public <T> T keyName(Generic<T> container){
            T test = container.getKey();
            return test;        }

        /** * this is not a Generic method, this is just a Generic method that uses the Generic<Number> class as its parameter. *@param obj
         */
        public void showKeyValue1(Generic<Number> obj){}/** * this is not a generic method, this is a normal method, but with generic wildcards? *@param obj
         */
        public void showKeyValue2(Generic
        obj){}/** * The method compiler will report an error * although we declare <T>, we also indicate that this is a generic method that can handle generic types. * But only the generic type T is declared, not E, so the compiler does not know what to do with E. *@param container
         * @param <T>
         * @return* /
        public <T> T showKeyName(Generic<E> container){
            return null; }}}Copy the code

See Githu GenericMethodDemo. Java

2.3.2 Use of generic methods

Generic methods can be used everywhere and in any scenario, but there is one very special case where generic methods occur in generic classes.

public class GenericFruit {

    class  Fruit{
        @Override
        public String toString(a) {
            return "fruit"; }}class Apple extends Fruit{
        @Override
        public String toString(a) {
            return "apple"; }}class Person{
        @Override
        public String toString(a) {
            return "Person"; }}class GenerateTest<T>{

        public void show_1(T t){
            System.out.println(t.toString());
        }

        // Declare a generic method in a generic class, using the generic type E, which can be of any type. It could be of the same type as T, or it could be different.
        // Since generic methods declare generics 
      
        when declared, the compiler can correctly recognize generics recognized in generic methods even if they are not declared in generic classes.
      
        public <E> void show_3(E t){
            System.out.println(t.toString());
        }

        // We declare a generic method in the generic class, using the generic T. Note that T is a completely new type and may not be the same type as T declared in the generic class.
        public <T> void show_2(T t){ System.out.println(t.toString()); }}@Test
    public void test(a) {

        Apple apple = new Apple();
        Person person = new Person();

        GenerateTest<Fruit> generateTest = new GenerateTest<Fruit>();
        // Apple is a subclass of Fruit, so this is ok
        generateTest.show_1(apple);
        // The compiler will report an error because the generic type argument is Fruit and the passed argument class is Person
        //generateTest.show_1(person);

        // Use both methods successfully
        generateTest.show_2(apple);
        generateTest.show_2(person);

        // Both methods can also be successfulgenerateTest.show_3(apple); generateTest.show_3(person); }}Copy the code

See Githu GenericFruitTest. Java

2.3.3 Static methods versus generics

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

If written as follows, the compiler will report an error

public staticvoid show(T t){}Copy the code
  • Correct way to write:
public static <T> void show(T t){}Copy the code

2.3.4 Summary of generic methods

Generic methods allow methods to change independently of classes. Here is a basic guideline:

Whenever you can, you should use the generic approach. That is, if you use a generic method to generalize an entire class, then you should use a generic method. In addition, for a static method, there is no access to the parameters of the generic type. So if a static method is to use generic capabilities, it must be generic.

Generic wildcards

When defining generic classes, generic methods, and generic interfaces, we often encounter different wildcards, such as T, E, K, V, and so on. What do these wildcards mean?

3.1 the commonly usedT,E,K,V,?

These are essentially wildcards, no difference, just conventions of coding. For example, in the above code, T can be replaced with any letter between A and Z without affecting the normal operation of the program. However, if T is replaced with other letters, the readability may be weaker. In general, T, E, K, V, right? Here’s the deal:

  1. ?: indicates uncertainjavaType;
  2. T (type): Indicates a specific onejavaType;
  3. K V (key value): Represent respectivelyjavaThe key value of theKey/Value;
  4. E (element)Representative:Element.

3.2 ?Unbounded wildcard

You can use unrestricted wildcards (a question mark in Angle brackets,
), indicating that any type can be held.

3.3 Upper bound Wildcards<? extends E>

Upper bound: Declared with the extends keyword to indicate that the parameterized type may be the specified type or a subclass of that type.

public void showKeyValue(Generic<? extends Number> obj){
    log.info("value is {}", obj.getKey());
}

@Test
public void testForUp(a) {
    Generic<String> generic1 = new Generic<String>("11111");
    Generic<Integer> generic2 = new Generic<Integer>(2222);
    Generic<Float> generic3 = new Generic<Float>(2.4 f);
    Generic<Double> generic4 = new Generic<Double>(2.56);

    /*// This line of code will cause an error because String is not a subclass of Number. * /

    showKeyValue(generic2);
    showKeyValue(generic3);
    showKeyValue(generic4);
}
Copy the code

Using extends in a type parameter means that the parameter in the generic must be E or a subclass of E. This has two benefits:

  1. If the type passed is notEorESubclass of, failed to compile;
  2. Can be used in genericsEOr you have to turn it intoETo use.

3.4 Lower bound wildcards<? super E>

Lower bound: declared with super, indicating that the parameterized type may be the specified type or a parent of the type, up to Object

Using super in type parameters indicates that the parameters in the generic must be E or a parent of E.

The upper and lower bounds of the generic must be added with the declaration of the generic

Instance code address

3.5 ?TThe difference between

? And T are indeterminate types, the difference is that we can operate on T, but right? No, like this:

/ / can
T t = operate();

/ / can't? car = operate();Copy the code

That is, T is a definite type, usually used in the definition of generic classes and generic methods. Is an indeterminate type that is usually used for calling code and parameters of generic methods and cannot be used to define classes and generic methods.

3.6 Class<T>Class<? >The difference between

Class

When instantiated, T is replaced with a concrete Class. Class
< span style = “box-sizing: border-box! Important; Can represent any type, so it is mainly used for declarative restrictions. For example, we can declare this:

/ / can
publicClass<? > clazz;// No, because T needs to specify the type
public Class<T> clazzT;
Copy the code

So when you don’t know what type of Class to declare, you can define a Class
. Public Class

clazzT; In this case, you have to make the current class also specify T,

public class Wildcard<T> {

    publicClass<? > clazz;public Class<T> clazzT;
}
Copy the code

4. What’s important about generics

4.1 Type Erasure

Generics information exists only during code compilation, and generic-related information is erased before entering the JVM, a technical term called type erasure.

public class GenericTypeErase {

    public static void main(String[] args) {
        List<String> l1 = new ArrayList<String>();
        List<Integer> l2 = newArrayList<Integer>(); System.out.println(l1.getClass() == l2.getClass()); }}Copy the code

Prints true; Because List

and List

are both list. classes in the JVM, the generic information is erased.

4.2 Generic classes or methods are not accepted8Basic data types

You need to use their corresponding wrapper classes.

4.3 JavaYou cannot create a generic array of a concrete type

List<Integer>[] li2 = new ArrayList<Integer>[];
List<Boolean> li3 = new ArrayList<Boolean>[];
Copy the code

List

and List

are JVM equivalent to List
. All type information is erased, and the program cannot tell whether the element type in an array is List

or List

.



4.4 Generics are strongly recommended

It separates data types from code logic, and is intended to improve program code’s brevity and readability, and to provide possible compile-time conversion safety checks.

Five, the summary

5.1 Sample Source code

Githu sample code

5.2 Reference Articles

  1. Overview of Generics in Java – this is definitely the most detailed overview of generic methods out there
  2. Talk about it – Wildcards T, E, K, V, JAVA generics?

5.3 Technical Communication

Github sample code

  1. Travelogue blog: https://www.dustyblog.cn
  2. Dust blog – Gold digging
  3. Travelogue Blog – Blog Garden
  4. Github
  5. The public,