What is generics
As a literal meaning, a generalized type means that a specific type cannot be determined during encoding. A placeholder (uppercase, English is recommended) needs to be used first. When running, a specific type is passed in to replace this generic tag
Why do I need generics
Pseudo demand
Suppose we need a list to store String data, the design of this structure is
class MyListForString{ String get(); void set(Sring int) }
Then, if you find that you need a list to access Integer type data, you need to redefine a structure
class MyListForInteger{ Integer get(); void set(Integer int) }
Then, we need a list to store xx type data..
Optimize with Object
To extract this requirement, we actually need to have a list structure, and then be able to store a specified type (this type may change according to needs), and we need to be able to correctly extract the corresponding type. Now, in order to cope with the changing requirements, we repeat writing almost MyListForXX
According to the knowledge points of polymorphism and upward transformation (for those who don't understand xdm, you can take a look at the pre knowledge points I prepared Three basic features of Java polymorphism ), we can use Object optimization to form the following code block
class MyList{ Object get(); void set(Object obj) }
Now we can achieve universality, that is, we should be careful when using emm
MyList list = new MyList(); list.set(1); list.set("1"); Integer a = (Integer)list.get(); // The type extracted from the code is actually Object. We need to manually force it to the type when saving String s = (String)list.get();
As the pseudo code demonstrates, there are no restrictions when we store data. However, if we take it out, we need to be careful. After all, no one knows what type of data is stored in the list. Maybe we can modify the description of instance creation to achieve a little non binding restrictions?
MyList listOnlyForInt = new MyList(); // Note the instance name list.set(1);
Generic Optimization
Perhaps fed up with this weak constraint, java finally introduced generics in JDK5
The advantage of modifying the above code with the idea of generics is obvious. When we create an instance of MyList, we tell the JVM that the instance type of generic T operated by this instance is String. The JVM will verify whether the data types match when we store the data, and automatically force it to the corresponding type when we take it out
There is no magic inside the JVM. The underlying type is still Object. However, the JVM will verify the input parameters and force the output parameters according to the specific generic types we pass
class MyList<T>{ T get(); void set(T int) } MyList<String> strs = new MyList<String>(); String s = strs.get();
java.util.ArrayList
Let's read the source code of get(), add() of the collection class ArrayList that we often use
1. The array of Object [] is actually used in the collection
2. add() stores the data into the Object array, which involves an upward transformation of the hidden operation (disguised verification, all class es are inherited from the Object)
3. get() forcibly converts the obtained data to the actual type of 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
So this is generics
From the above example, careful students should find, "eh, I used generic duck to write list, set and map?"
Write a few casually:
List<String> list = new ArrayList<>(); Set<Integer> set = new HashSet<>(); HashMap<String, User> hashMap = new HashMap<>();
Yes, that's the basic use of generics
Boundary of generics
In the generic world, there are actually similar inheritance relationships, such as < T extensions string >, < T super string >
extends
class MyList<T extends String>{ T get(); }
This code doesn'T seem to have changed much. The only difference is that generic T is a type inherited from String
In addition, because of the inheritance relationship, we can obtain any type of generic instance T, transform them upward and treat them as a String, and then actually call the corresponding methods in generic T through the idea of polymorphism
super
class MyList<T super String>{ void set(T int) }
It can be understood that the generic T passed in at runtime is the parent class of String, and the specific parent class is unknown
Differences between extensions and super
The difference between super and extensions is that generic operations using < T extensions XXX > can be treated as XXX. Generics using < T super XXX > can only pass the instance corresponding to 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
From the above code, although ArrayList declares specific generics or does not have generics, their corresponding classes are all the same? In disguise, there is no trace of generics in class?
Generics on Methods
Although the whole article talks about generics in class, in fact, generics can also be applied and used in methods
However, generics cannot be initialized directly. We need to pass in a specific generic instance or the corresponding generic class
The definition format of generic method is [scope] [static] < T > t method name (parameter list)
Take a jsonutil I encapsulated Toobject(), for example, is defined as public static < T > 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) { // Alternatively, we can pass in a specific instance of the generic, but this is very rare toObject(json, t.getClass()); } // Pseudo code call User user = JsonUtil.toObject(jsonStr, User.class);
Generic Tags
In this article, the tag T is widely used to represent generics. We can also replace it with other symbols, but it is required to declare that this is a generic operation in the way of < tag >, such as demonstration code
class List<E>{} <A> A get(); <A, B, C> Tuple<A,B,C> tupleInstance(){}
tuple
Forget to introduce a fun structure with generics, tuple. The meaning of this data structure is to return multiple parameters for the method. Of course, we can also use map and list, but it is not as elegant as tuple
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; } }
Just like initializing an ordinary class, there is no difference in usage. The change is the two fields inside the tuple. Their classes are determined at runtime. We can change their types at will when necessary
Tuple<Integer, String> tuple = new Tuple<>(1, "1"); Integer a = tuple.a; String b = tuple.b;
# ❤ last
It's not easy to create. If this blog is helpful to you, I hope you can click three times!, Thanks for your support. I'll see you next time~~~