This is the 22nd day of my participation in the August Wen Challenge.More challenges in August

What is a generic

A generic type, as it is literally called, means that a specific type cannot be determined at coding time, requiring a placeholder (upper case, full English recommended), which is passed in at runtime to replace the generic flag with a specific type

Why generics

Pseudo demand

Suppose we need a list to store String data

class MyListForString{
  String get(a);
  void set(Sring int)
}
Copy the code

Then, if you find that you need a list to access data of type Integer, you need to redefine a structure

class MyListForInteger{
  Integer get(a);
  void set(Integer int)
}
Copy the code

Then we need a list to store data of type XX.

With the Object optimization

To extract this requirement, we need to have a list structure, and be able to store a specified type (which may change as needed), and need to be able to retrieve the corresponding type correctly. Now, in response to the changing requirements, we write the same MyListForXX repeatedly

According to the knowledge of polymorphism and up transition, we can use Object optimization into the following code block

class MyList{
  Object get(a);
  void set(Object obj)
}
Copy the code

Now it can be universal, is to use, EMM, have to be careful

MyList list = new MyList();
list.set(1);
list.set("1");
Integer a = (Integer)list.get();  // The type retrieved from the code is actually Object, and we need to manually force it to be the type saved
String s = (String)list.get();
Copy the code

As the pseudocode demonstrates, there are no restrictions on how we store data, but we need to be careful about how we retrieve it. After all, you never know what kind of data is stored in the list. Maybe we can modify the description of instance creation to implement a little bit of a non-binding restriction?

MyList listOnlyForInt = new MyList();  // Note the instance name
list.set(1);
Copy the code

The generic optimization

Perhaps fed up with such weak constraints, Java finally introduced generics in JDK5

When we create an instance of MyList, we tell the JVM that this instance operates on a generic T instance of type String. The JVM verifies that the data we store matches the data type, and when we retrieve the data, Automatic strong conversion to the corresponding type

There is no magic in the JVM. The underlying type used is Object. However, the JVM does validation for incoming and outgoing parameters based on the specific generic type we pass

class MyList<T>{
  T get(a);
  void set(T int)
}
MyList<String> strs = new MyList<String>();
String s = strs.get();
Copy the code

java.util.ArrayList

Take a look at the source code for get() and add() of ArrayList, the collection classes we often use

1, The collection actually uses an array of Object[]

2. Add () stores data into an array of Objects, which involves a hidden upturn operation (disguised validation, all classes inherit from Object).

3, get() on the obtained data, forcibly cast to the actual type of the generic E

public E get(int index) {	// line: 432
  rangeCheck(index);
  return elementData(index);
}
E elementData(int index) {  // line: 421
  return (E) elementData[index];
}
public boolean add(E e) {  // line: 461
  ensureCapacityInternal(size + 1);  // Increments modCount!!
  elementData[size++] = e;
  return true;
}
transient Object[] elementData; // non-private to simplify nested class access // line: 135
Copy the code

So that’s what generics are

From the above example, careful students should have noticed, “Oh, so I write List, Set, Map those sets of operations using generic duck?”

Jot down a few:

List<String> list = new ArrayList<>();
Set<Integer> set = new HashSet<>();
HashMap<String, User> hashMap = new HashMap<>();
Copy the code

Yes, the basic use of generics is just that

The boundary of a generic

In the generics world, there are things like inheritance, such as

,

extends

class MyList<T extends String>{
  T get(a);
}
Copy the code

This code doesn’t look much different, the only difference being that the generic T inherits from some type of String

In addition, because of inheritance, we can take any type of generic instance T and cast them up asStringProcess, and then use the idea of polymorphism to actually call the corresponding method in the generic T

super

class MyList<T super String>{
  void set(T int)
}
Copy the code

T is the parent of String, but I don’t know what level it is

The difference between extends and super

The difference between super and extends is that generic operations that use

can be treated as XXX, whereas generics that use

can only pass the corresponding instance of XXX to generic type processing

Type erasure

Class c1 = new ArrayList<String>().getClass();
Class c2 = new ArrayList<Integer>().getClass();
Class c3 = new ArrayList().getClass();
System.out.println(c1 == c2);	// true
System.out.println(c1 == c3);	// true
Copy the code

From the above code, arrayLists declare specific generics, or no generics, but their corresponding classes are all the same. In class, there is no trace of generics at all. Right?

Generics on methods

Although this whole article is about generics in class, in fact, generics can also be applied to methods

However, there is no way to initialize a generic directly, so we need to pass in a specific instance of the generic, or the corresponding genericclass

Generic methods are defined in the format [scope] [static]

T method name (parameter list)

For example, I wrapped a jsonutil.toobject (). The definition of this method is public static

T toObject()

public static <T> T toObject(String json, Class<T> clz) {
  if (json == null) {
    try {
      return clz.newInstance();
    } catch (Exception e) {
      LogUtil.exception("JsonUtil.toObject: <T>", e); }}return json_.toObject(json, clz);
}
public static <T> T toObject(String json, T t) {	// Or we could pass in a concrete instance of the generic, but this would be very rare
  toObject(json, t.getClass());
}
// pseudo code call
User user = JsonUtil.toObject(jsonStr, User.class);
Copy the code

The markup for generics

In this article, the flag T is used extensively to denote generics. We can use other symbols to denote generics, but all require that the < flag > is used first to declare that this is a generic operation, such as demo code

class List<E>{}

<A> A get(a);

<A, B, C> Tuple<A,B,C> tupleInstance(a){}
Copy the code

tuples

I forgot to introduce one of the funniest structures with generics, tuples. The point of this data structure is to return multiple parameters to a method. Of course, we can do this with maps and lists, but it’s not as elegant as tuples

First, we define a tuple structure that returns two generic types

class Tuple<A.B>{
  final A a;
  final B b;
  public Tuple(A a1, B b1){ a = a1; b = b1; }}Copy the code

Just like initializing a normal class, there is no difference in usage. The difference is that the two fields inside the tuple have their classes determined at runtime, and we can change their types as needed

Tuple<Integer, String> tuple = new Tuple<>(1."1");
Integer a = tuple.a;
String b = tuple.b;
Copy the code

So much for generics in Java, and the likes and favorites HXD has given me are the biggest encouragement