Usually when we look at some source code, we find all T,? Dizzy dizzy dizzy dizzy dizzy dizzy So it’s important to get generics right!

What are generics

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

The nature of generics is parameterized typing, which means that the data type being operated on is specified as a parameter.

What are the benefits of generics? Write an example at a glance:

We will encapsulate a message response class:

public class Result implements Serializable {

    / / the response code
    Integer code;

    // Check whether it succeeds
    Boolean success;

    // Return body data
    User user;

    public Result(Integer code, Boolean success, User user) {
        this.code = code;
        this.success = success;
        this.user = user;
    }

    @Override
    public String toString(a) {
        return "Result{" +
                "code=" + code +
                ", success=" + success +
                ", user=" + user +
                '} ';
    }

    public static void main(String[] args) {

        User user = new User(1."Tony");
        Result result = new Result(200.true, user); System.out.println(result); }}class User implements Serializable {

    Integer id;

    String name;

    public User(Integer id, String name) {
        this.id = id;
        this.name = name;

    }

    @Override
    public String toString(a) {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\' ' +
                '} '; }}Copy the code
Result{code=200, success=true, user= user {id=1, name='Tony'}} The process has ended, exit code 0Copy the code

The responder can then return the request status and user information. Now that we need to return information about the phone, we need to encapsulate a response class that returns information about the phone… There are clothes, shoes… Do you have to work to death? This is where generics come in:

public class Result<T> implements Serializable {

    / / the response code
    Integer code;

    // Check whether it succeeds
    Boolean success;

    // Return body data
    T data;

    public Result(Integer code, Boolean success, T data) {
        this.code = code;
        this.success = success;
        this.data = data;
    }

    @Override
    public String toString(a) {
        return "Result{" +
                "code=" + code +
                ", success=" + success +
                ", data=" + data +
                '} ';
    }

    public static void main(String[] args) {

        User user = new User(1."Tony");
        Result<User> resultUser = new Result<>(200.true, user);
        System.out.println(resultUser);
        Phone phone = new Phone(999.99."Yellow");
        Result<Phone> resultPhone = new Result<>(200.true, phone); System.out.println(resultPhone); }}class User implements Serializable {

    Integer id;

    String name;

    public User(Integer id, String name) {
        this.id = id;
        this.name = name;

    }

    @Override
    public String toString(a) {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\' ' +
                '} '; }}class Phone implements Serializable {

    Double price;

    String color;

    @Override
    public String toString(a) {
        return "Phone{" +
                "price=" + price +
                ", color='" + color + '\' ' +
                '} ';
    }

    public Phone(Double price, String color) {
        this.price = price;
        this.color = color; }}Copy the code
Result{code=200, success=true, data=User{id=1, name='Tony'}} Result{code=200, success=true, data=Phone{price=999.99, Color ='Yellow'}} Process terminated, exit code 0Copy the code

As you can see, using generics, you can uniformly identify the entity class that needs to be returned. No matter what class you come in, I can fit it in for you!

The first contact may not be very clear, the following details

Generic method

You can write a generic method that accepts different types of arguments when called. The compiler handles each method call appropriately, depending on the type of argument passed to the generic method.

Grammar rules

  • All generic method declarations have a type parameter declaration section (separated by Angle brackets) that precedes the method return type

Let’s say this is a generic method that prints an array:

private static <E> void printArray(E[] inputArray)
Copy the code
  • Each type parameter declaration section contains one or more type parameters separated by commas. A generic parameter, also known as a type variable, is an identifier used to specify the name of a generic type.

Like this method

private static <E,T> void printArray(E[] inputArray, T data)
Copy the code
  • Type parameters can be used to declare return value types and can serve as placeholders for the actual parameter types derived from generic methods.

  • The generic method body is declared just like any other method. Note that type parameters can only represent reference types, not primitive types (int double char, etc.).

Generic token

  • E Element Set Element
  • T Type Java classes
  • K Key Key
  • V Value Value
  • N Number Indicates the value type
  • ? Represents an indeterminate Java type

These flags are not restricted to the corresponding type, and the compiler will not error if you use only one of the a-Z characters. The reason for the different tags is that this is a convention. ** Many rules in development are conventions that improve the readability of our code and make it easier for teams to collaborate

Write a complete example:

public class TFunction {

    public static void main(String[] args) {

        // Create various types of arrays
        Integer[] intArray = {1.2.3.4.5};
        Double[] doubleArray = {1.1.2.2.3.3.4.4};
        Character[] charArray = {'H'.'E'.'L'.'L'.'O'};

        System.out.println("Integer array elements are :");
        printArray(intArray); // Pass an array of integers

        System.out.println("\n Double array elements are :");
        printArray(doubleArray); // Pass a double array

        System.out.println("\n array elements are :");
        printArray(charArray); // Pass an array of characters

    }

    // Generic methods
    private static <E> void printArray(E[] inputArray) {

        // Iterate over the print array
        Arrays.stream(inputArray).forEach(e -> {
            System.out.printf("%s ", e); }); System.out.println(); }}Copy the code

A generic class

The declaration of a generic class is almost identical to that of a non-generic class, except that a parameter declaration section is added to the end of the class name

I won’t give you an example here, because the first example encapsulates a generic class, so you can go back and look at it if you don’t understand it at the time

Type wildcard

?

We can usually use? To undertake all reference types, carry a rookie example:

public class GenericTest {
     
    public static void main(String[] args) {
        List<String> name = new ArrayList<String>();
        List<Integer> age = new ArrayList<Integer>();
        List<Number> number = new ArrayList<Number>();
        
        name.add("icon");
        age.add(18);
        number.add(314);
 
        getData(name);
        getData(age);
        getData(number);
       
   }
 
   public static void getData(List
        data) {
      System.out.println("data :" + data.get(0)); }}Copy the code
data :icon
data :18
data :314
Copy the code

? extends T

This is the upper boundary of the ** generic: ** Only subclasses of T objects can be passed in

If it is? Extends C, then only D and E are allowed to be passed, otherwise an error is reported

? super T

This is the lower boundary of the ** generic: ** Only the superclass of T objects can be passed in

If it is? Super D, then only C and A are allowed to be passed in, otherwise an error will be compiled

T and?

I don’t know if there’s any confusion here. T and? It seems to work about the same. What’s the difference?

Just to explain, T is a generic parameter, and? Is more used for an indeterminate reference type

T and Object

The highlight!!

Those of you who know Object know that it is a Java superclass (the parent class of all objects). If you don’t, check out my blog for a detailed explanation.

The problem is that Object can replace generics. Any place you can use generics, Object can!

In fact, before JDK5, we used Object, but there were a lot of problems with it. After JDK5, we introduced generics

Object is the parent of all classes, it is inevitable to have type conversion problems in the coding process, and will not report errors in the compilation stage, until the run stage exposed problems, greatly reducing the safety and robustness of the program!

Here are some examples of the classification of transformation:

  • For example: Animal is the parent of Cat. We declare it like this:
  Animal cat = new Cat();
Copy the code
  • Downward transition

    Force a superclass object to an instance of its subclass:

Animal cat = new Cat();
Cat anotherCat = (Cat) cat;
Copy the code

So when we use Object as a generic type, not only is it difficult to write, but it also has to be converted constantly, and it is very easy to have problems

Here’s an example:

We define a numeric variable with Object, which we generically cast down to Integer and String. Converting a number to a string is a ridiculous thing, and the compiler doesn’t notice until the program is running…

Type conversion exception!!

conclusion

With the advent of generics, problems with type conversion are exposed at compile time. It solves many problems existing in Object, making the code more elegant, the program more secure and more robust.