This is the third day of my participation in the August Text Challenge.More challenges in August

Generics are one of the advanced features of Java. If you want to write elegant and extensible code, or if you want to read some good source code, generics are the barrier to escape.

primers

I wanted to write about some of the advanced features of Java that you might not need to do normal business, but that you can’t avoid if you want to write elegant and extensible code or read good source code.

If you do not understand these features, not familiar with the characteristics of application scenarios, and when using difficult because the grammar and other reasons, it is hard to overcome the inertia to use them, so there are always some colleagues around, work for many years, but never useful some advanced features of the Java, write the code is always bad so a little feeling.

In case your code is still very low in a few years, be prepared to take a closer look at these features now. This article starts with the most common generics.

What is the

First, what generics are. The English word generic is generic, Chinese meaning generic, class, combined with its application scenarios, I understand that generic is a kind of generic type. But we generally refer to generics by the way they are implemented, which is to parameterize types

In a strongly typed language like Java, without generics, it can be cumbersome to handle the need for different types of the same logic.

If you want to write a quick sort of int:

public static void quickSort(int[] data, int start, int end) {
    int key = data[start];
    int i = start;
    int j = end;
    while (i < j) {
        while (data[j] > key && j > i) {
            j--;
        }
        data[i] = data[j];
        while (data[i] < key && i < j) {
            i++;
        }
        data[j] = data[i];
    }
    data[i] = key;
    if (i - 1 > start) {
        quickSort(data, start, i - 1);
    }
    if (i + 1 < end) {
        quickSort(data, i + 1, end); }}Copy the code

However, if the requirements have changed and we now need to implement fast sorting of both int and long, then we need to use the Java class method overload, copy the above code, change the parameter type to double and paste it again. But if you want to implement quicksort for floats, doubles, even strings, and all sorts of classes, wouldn’t it be too inelegant to copy and paste code every time you add a type?

Of course, we can also declare the passed parameter Object, and when comparing the size of two elements, determine the element type, and use the corresponding method to compare. This way, the code is sick of making type judgments. A small range of inelegance does not solve the problem.

At this point, we consider using generic types (generics) to set the parameters of the quicksort method to a generic type, so that whatever parameters are passed in and sorted as long as the Comparable interface is implemented.

public static  <T extends Comparable<T>> void quickSort(T[] data, int start, int end) {
    T key = data[start];
    int i = start;
    int j = end;
    while (i < j) {
        while (data[j].compareTo(key) > 0 && j > i) {
            j--;
        }
        data[i] = data[j];

        while (data[i].compareTo(key) < 0 && i < j) {
            i++;
        }
        data[j] = data[i];
    }
    data[i] = key;

    if (i - 1 > start) {
        quickSort(data, start, i - 1);
    }
    if (i + 1 < end) {
        quickSort(data, i + 1, end); }}Copy the code

So, to summarize the application scenarios of generics, we can consider using generics when encountering the following scenarios:

  • When the parameter type is not clear and may be extended to multiple types.
  • If you want to declare the parameter type as Object and use instanceof when using it.

Note that generics can only replace subtypes of Object. If you need to replace primitive types, you can use wrapper classes. Why?

How to use

Generic types are declared in the form of < placeholder [, another placeholder] >, separated by, when multiple placeholders need to be declared in one place. There is no limit to the format of the placeholder, but the convention is to use a single uppercase letter, such as T for type, E for element *, and so on. Although there are no strict rules, it is a good idea to check convention usage before using the code for legibility.

Generics refer to a parameter type that can be declared on classes, methods, and interfaces.

A generic class

class Generics<T> { // Declare the introduction of generic types after the class name
    private T field;  // Fields can be declared as generic types after being introduced

    public T getField(a) { // Generic types can also be used within class methods
        returnfield; }}Copy the code

Generic method

public [static] <T> void testMethod(T arg) { After declaring a generic method with < placeholder > after static, you can use the generic type after the argument list
    // doSomething
}
Copy the code

call

Then there are the generic calls, which are not much different from ordinary method or class calls, as follows:

 public static void main(String[] args) {
  String[] strArr = new String[2];
  	 // Generic methods are called the same as normal methods
  	 Generics.quickSort(strArr, 0.30 );
     // A generic class needs to declare an exact type when called
     Generics<Long> sample = new Generics<>();
     Long field = sample.getField();
    }

    // Generic interfaces need to be implemented in generic classes
    class GenericsImpl<T> implements Comparable<T> {
    @Override
    public int compareTo(T o) {
        return 0; }}Copy the code

summary

Taking a good look at generics, it feels like a lot of work, and a bit of Java fog has been lifted. These features can be quite difficult, and when you think you’ve understood them well enough, you feel later that you haven’t understood them well enough. It’s important to practice, and it’s easy to find confusion when you use them.