Use Java partners, for some advanced Features of Java must be familiar with, such as collection, reflection, generics, annotations and so on, these can be said that we are often used in peacetime development, especially collection, basic is as long as the code is not less than, today we first to talk about generics.

Definition 1.

Before we can understand a thing, we must know its definition, so we start with the definition, to uncover the mystery of generics step by step.

Generics is a new feature introduced in JDK5. Generics provides a compile-time type safety monitoring mechanism that allows us to detect illegal type data structures at compile time. The nature of generics is parameterized type, that is, the data type being operated on is specified as a parameter. # Common types of generics indicate that the T above is just like a parameter. The name is actually arbitrary, but we should always write code to be readable. Common arguments are: e-element (used in collections, because collections contain elements) T-type (Representing Java classes, both basic and our own) K-key (representing keys, such as keys in maps) V-value (representing values)? - (indicates an undefined Java type) But the parameters of a generic type can only be class types, not basic data types, its type must be from ObjectCopy the code

Note: Generics do not accept primitive data types; in other words, only reference types can be used as actual parameters to generic methods

2. Why generics?

When it comes to why you should use it, it must be a list of things you can convince yourself of.

# The introduction of generics is a major enhancement in the Java language. There have also been some enhancements to the compiler. To support generics, Java class libraries have been modified to support generics. (Popular science: Java generics were not actually introduced in JDK5 (it was released in 2004), the generics mechanism was one of the earliest specifications in Java back in 1999)Copy the code

In addition, generics have the following advantages:

# 1. Commit Java's type safety Generics greatly improve Java's program safety. For example, in the absence of generics, it is easy to convert a String 123 to an Integer 123 or an Integer to a String, and such errors cannot be detected at compile time. Using generics is a good way to avoid this. Generics eliminate casts because the programmer already knows what type to use at the time of development. This makes code more readable and more robust. Programming generics means that you can write code that can be reused by many different types of objectsCopy the code

Prior to the publication of the generic specification, generic programming was implemented through inheritance, but this had two serious problems:

(1) The value must be cast; otherwise, all objects are returned

② No error checking at compile time

Let’s look at these two errors

2.1 There will be no error checking at compile time

public class DonCheckInCompile { public static void main(String[] args) { List list = new ArrayList(); list.add("a"); list.add(3); System.out.println(list); }}Copy the code

Program not only will not report errors, but also normal output

2.2 Cast Type

public class DonCheckInCompile { public static void main(String[] args) { List list = new ArrayList(); list.add("a"); list.add(3); for (Object o : list) { System.out.println((String)o); }}}Copy the code

Because you don’t know exactly what types of elements are in the actual set, you can’t be sure when you use it. If you do strong rotation, it will inevitably bring unexpected errors, so that the potential problem is like a time bomb and must not be allowed to happen. So this is all the more important for generics.

3. Generic methods

In Java, generic methods can be used in member methods, constructors, and static methods. The syntax is as follows:

Public < declare the type of the generic > type parameter fun(); Public T fun(T T); Where T represents a generic type, it means that we define a type of T so that T can be used directly and needs to precede the return type of the method. T is not a class, but it can be used as a type.

To illustrate this, the following code swaps elements at two subscripts specified in an array (regardless of the actual requirements). The first type of array is an Integer

public class WildcardCharacter { public static void main(String[] args) { Integer[] arrInt = {1, 2, 3, 4, 5, 6, 7, 8, 9}; change(arrInt, 0, 8); System.out.println("arr = " + Arrays.asList(arrInt)); } /** * swap the array with the specified two subscript positions ** @param arr array * @param firstIndex the first subscript * @param secondIndex the second subscript */ private static void  change(Integer[] arr, int firstIndex, int secondIndex) { int tmp = arr[firstIndex]; arr[firstIndex] = arr[secondIndex]; arr[secondIndex] = tmp; }}Copy the code

The second is a String array

If you pass a String[], it will not pass. So we can only define one more parameter of type String[].

What about another Double? Boolean? This is a problem, although it is not fatal and can be solved by writing more repetitive code, but it inevitably leads to code redundancy and increased maintenance costs. So this is where generics come in, and we change it to generics.

/** * @param t * @param firstIndex * @param secondIndex * @param < t > */ private static <T> void changeT(T[] T, int firstIndex, int secondIndex) {T TMP = T[firstIndex]; t[firstIndex] = t[secondIndex]; t[secondIndex] = tmp; }Copy the code

The next call is simple

Public static void main(String[] args) {// Define an array of type Integer Integer[] arrInt = {1, 2, 3, 4, 5, 6, 7, 8, 9}; ChangeT (arrInt, 0, 8); System.out.println("arrInt = " + Arrays.asList(arrInt)); / / and then define a String of type String array [] arrStr = {" a ", "b", "c", "d", "e", "f", "g"}; ChangeT (arrStr, 0, 1); System.out.println("arrStr = " + Arrays.asList(arrStr)); }Copy the code

Solved the problem, as for ordinary generic methods and the use of static generic method is same, only is a data class a belongs to class instances, on the use of the difference is not big, but it is important to note if static generic method in a generic class is class cannot be used in the generic generic types, the generic class below) will be introduced in.

Finally, let’s look at the constructor

public class Father {
    public <T> Father(T t) {
    }
}
Copy the code

And then let’s say he has a subclass that looks like this

class Son extends Father { public <T> Son(T t) { super(t); }}Copy the code

It is important to note that since there is no parameterless constructor in the Father class, there is a parameterless constructor in the Father class, except that the constructor is a generic method, such a subclass would need to specify the constructor explicitly.

  • Get the element tests in the collection through generic methods

Since generics are declared when the type is not important, as long as the use of things can be determined, then you see how to interpret the following?

When you try to add elements to the collection, you get such an error that you can’t even compile it. Why is that?

Since T is a generic type, the type of T can only be determined at the time of use. However, the type of T cannot be determined at the time of use. Therefore, the add method cannot be used at all, unless list.add(null). But it doesn’t make any sense.

4. A generic class

Let’s take a look at a code that uses multiple generic methods, regardless of what the method actually does

Public class GenericClassTest{public static void main(String[] args) {// Define an array of type Integer Integer[] arrInt = {1, 2, 3, 4, 5, 6, 7, 8, 9}; New GenericClassTest().changet (arrInt, 0, 8); System.out.println("arrInt = " + Arrays.asList(arrInt)); List<String> list = Arrays.asList("a", "b"); testIter(list); } /** * @param t parameter type t * @param firstIndex * @param secondIndex second subindex * @param < t > */ private <T> void changeT(T[] T, int firstIndex, int secondIndex) {T TMP = T[firstIndex]; / / private <T> void changeT(T[] T, int firstIndex, int secondIndex); t[firstIndex] = t[secondIndex]; t[secondIndex] = tmp; } @param <T> defines a type of T, otherwise no one knows what T is, */ private static <T> void testIter(List<T> List) {for (T T: List) {system.out.println (" T = "+ T); }}}Copy the code

You can see if every method in the list needs to be declared once, but how about 100 methods? Does that have to be declared 100 times, so that the generic class is born. So what does a generic class look like? Please look at the code

Public class GenericClazz<T>{// This is what a basic generic class looks like}Copy the code

Let’s optimize the code as follows, but I have to mention a very basic but little-noticed problem. See the text description in the screenshot below.

Why does an instance method work, but a static method fails? Static methods cannot use class-defined generics. Instead, they should define generics separately. Static methods are called directly by class, while ordinary methods must be called by instance. When a class calls a static method, the generic class behind it has not been created, so it must not be called this wayCopy the code

So static methods in the generic class can be written this way

Private static <K> void testIter(list <K> list) {for (K t: list) { System.out.println("t = " + t); }}Copy the code
  • Multiple generic types are used simultaneously

We know that maps exist as key-value pairs, so what if we use generic types for both the Key and Value of the Map? A static method can do the same, as shown in the following code

public class GenericMap { private static <K, V> void mapIter(Map<K, V> map) { for (Map.Entry<K, V> kvEntry : map.entrySet()) { K key = kvEntry.getKey(); V value = kvEntry.getValue(); System.out.println(key + ":" + value); } } public static void main(String[] args) { Map<String, String> mapStr = new HashMap<>(); mapStr.put("a", "aa"); mapStr.put("b", "bb"); mapStr.put("c", "cc"); mapIter(mapStr); System.out.println("======"); Map<Integer, String> mapInteger = new HashMap<>(); mapInteger.put(1, "11"); mapInteger.put(2, "22"); mapInteger.put(3, "33"); mapIter(mapInteger); }}Copy the code

So far, generic methods and generic classes have been introduced for.

5. A wildcard

The wildcard? The meaning of a placeholder is that the type of a placeholder cannot be determined during use, only specified for future actual use, and it has three forms

  • An unqualified wildcard character. Is to allow generics to accept data of ** unknown types **
  • A wildcard with an upper limit. E is the upper boundary of the generic type that accepts data of the specified class and its subclass types
  • Wildcard with ** lower bound **. E is the lower boundary of a generic that accepts data of the specified class and its parent type

5.1 Wildcard

As mentioned above, the use of a type to indicate reflection type must be declared, i.e., can’t generics be used without the declaration? Of course not. The <? “> < p style =” max-width: 100%; clear: both; min-height: 1em;

And since any type is a subclass of Object, we can use Object to receive, for? The specific use of “is described in the following two sections

Also, it’s important to understand that generics and wildcards are not the same thing

5.2 Wildcard

Ok, about generics, that’s all for today, thank you for your support!

Like this article friends, welcome to pay attention to the public number programmer xiao Grey, watch more exciting content