当前位置:网站首页>2021-03-14 - play with generics
2021-03-14 - play with generics
2022-07-08 01:17:00 【Mengqi D Xiaowu】
Generic
Write it at the front : Generic programming (Generic programming) It means that the code can be reused by many different types of objects .
Catalog
4 Generic does not allow subtypes
5.1.1 Class erasure 、 Method erase
5.2 Translate generic expressions
7.2 ArrayList in addAll Method
1 Generic (generic)
Generic stay J2E1.5 Introduced , Introduction in , In short , Generics are defining classes , Interfaces and methods make types ( Classes and interfaces ) Become a parameter . Very similar to the more familiar formal parameters used in method declarations , Type parameters provide you with a way to reuse the same code with different inputs . The difference is that the input of formal parameters is value , The input of type parameter is type .
JDK Is to check the type at compile time , Provides compile time type security . It's a collection The framework increases the security of compile time types , And eliminates the heavy type conversion work .
2 Why use generics
stay JDK5.0 before , If the return value of a method is Object , A collection is filled with Ob ject , Then getting the return value or element can only be forced , If there is a type conversion error , The compiler cannot detect , This greatly increases the probability of program errors , Quality must be guaranteed through continuous testing , Wouldn't it be nice if it could be solved at compile time ?
3 Reusability of generics
obviously , We all know Java The reusability of code is high , But how to realize the so-called reusability ???
This example , You can also skip , After reading the wildcards 、 upper bound 、 Look back at the lower bound .
For reusability of generics , Let's take a direct example :
Take a simple example , Bubble sort the array , Then we can easily write a bubble sort as follows :
//N A number bubble sort , All in all N-1 A comparison , The sorting times of each trip are (N-i) Compare it to
public static void bubbleSort(int[] arr){
// Remember to judge the boundary conditions , Many people don't pay attention to these details , The interviewer doesn't bother to look down when he sees your code , Which project of your code dares to add ?
if(arr==null||arr.length<2){
return;
}
// Need to carry out arr.length A comparison
for(int i = 0 ;i<arr.length-1;i++){
// The first i A comparison
for(int j = 0 ;j<arr.length-i-1;j++){
// Start a comparison , If arr[j] Than arr[j+1] It's worth a lot , Then swap places
if(arr[j]>arr[j+1]){
int temp=arr[j];
arr[j]=arr[j+1];
arr[j+1]=temp;
}
}
}
}Obviously , This function can deal with the sorting of integer arrays , But for a floating-point array , Then this function cannot handle , The preliminary improvements are as follows :
Maybe you'll say , It can be changed to a floating point , Then you can handle both integer and floating-point types
public static void bubbleSort(double[] arr) {
boolean flage = true;
for (int i = 0; flage && i < arr.length - 1; i++) {
flage = false;
for (int j = 0; j < arr.length - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
double temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
flage = true;
}
}
}
}Improve... Again :
- What if it is for a character array ????
- If it is for a string array ???
- What if I want to sort from small to large and from large to small ???
- What if I want to sort people according to their weight ????
Obviously, what we need is an array element that can be processed arbitrarily , A way to determine the attributes to compare :
public static <T> void bubbleSort(T[] arr, Comparator cmp) {
boolean flage = true;
for (int i = 0; flage && i < arr.length - 1; i++) {
flage = false;
for (int j = 0; j < arr.length - i - 1; j++) {
if (cmp.compare(arr[j], arr[j + 1]) > 0) {
T temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
flage = true;
}
}
}
}Now we can deal with the case that the array elements are arbitrary , Just create unused comparators according to your own needs
import java.util.Comparator;
public class FirstMin implements Comparator<Integer> {
@Override
public int compare(Integer i1, Integer i2) {
return i2 - i1;
}
}
import java.util.Comparator;
public class FirstMax implements Comparator<Integer> {
@Override
public int compare(Integer i1, Integer i2) {
return i1-i2;
}
}Last :
Because there is a problem involved in it ,“ Worker ”,“ Student ” All are “ people ”, The two can obviously compare weight .
But the object of the comparator can only be one
So the function must be modified
public static <T> void bubbleSort(T[] arr, Comparator<? super T> cmp) {
boolean flage = true;
for (int i = 0; flage && i < arr.length - 1; i++) {
flage = false;
for (int j = 0; j < arr.length - i - 1; j++) {
if (cmp.compare(arr[j], arr[j + 1]) > 0) {
T temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
flage = true;
}
}
}
}Come here , Maybe everyone , Don't know much about , The upper and lower bounds of generics are introduced in detail later .
4 Generic does not allow subtypes

The answer is yes . Why? ?
Suppose that , Can it be changed into the following situation , stay JDK All classes in are Object Subclasses of , If subtype is allowed , that ls You can store any type of elements in , This is completely contrary to the type constraints of generics , therefore JDK There are strict constraints on the verification of generics .
5 Generic rules
5.1 Type Erasure
5.1.1 Class erasure 、 Method erase
Write two pieces of code at will , A paragraph uses generic , Not for a while . After compilation , Generated .class The file is exactly the same as the original code , It's like the type information passed is erased again .( The specific code will not be repeated )
jdk1.5 Previous code
public class Node{
private Object obj;
public Object get(){
return obj;
}
public void set(Object obj){
this.obj=obj;
}
public static void main(String[] argv){
Student stu=new Student();
Node node=new Node();
node.set(stu);
Student stu2=(Student)node.get();
}
}Code that uses generics
public class Node<T>{
private T obj;
public T get(){
return obj;
}
public void set(T obj){
this.obj=obj;
}
public static void main(String[] argv){
Student stu=new Student();
Node<Student> node=new Node<>();
node.set(stu);
Student stu2=node.get();
}
}Generated by two versions .class file
public Node();
Code:
0: aload_0
You can see that generics is when you use generic code , Pass type information to specific generic code . After compilation , Generate
Of .class The file is exactly the same as the original code , It's like the type information passed is erased again .
Methods erase cases
Compiler bridging
1: invokespecial #1 // Method java/lang/Object."<init>":
()V
4: return
public java.lang.Object get();
Code:
0: aload_0
1: getfield #2 // Field obj:Ljava/lang/Object;
4: areturn
public void set(java.lang.Object);
Code:
0: aload_0
1: aload_1
2: putfield #2 // Field obj:Ljava/lang/Object;
5: return
}
// Second document
public class Node<T> {
public Node();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":
()V
4: return
public T get();
Code:
0: aload_0
1: getfield #2 // Field obj:Ljava/lang/Object;
4: areturn
public void set(T);
Code:
0: aload_0
1: aload_1
2: putfield #2 // Field obj:Ljava/lang/Object;
5: return
}
5.1.2 Compiler bridging
The bridging method is JDK 1.5 When generics are introduced , In order to make Java Bytecode and generated by the generic method of 1.5 Compatible with bytecode before version , Methods automatically generated by the compiler .
package com.naixue.vip.p6.bridging;
/**
* @Description
* @Author
**/
public class Node<T> {
public T data;
public void setData(T data) {
this.data = data;
}
public Node(T data) {
System.out.println("Node.setData");
this.data = data;
}
public static class MyNode extends Node<Integer>{
public MyNode(Integer data) {
super(data);
}
@Override
public void setData(Integer data) {
System.out.println("MyNode.setData");
super.setData(data);
}
// Simulate the bridge method generated by the compiler
// public void setData(Object data){
// setData((Integer)data);
// }
}
public static void main(String[] args) {
MyNode mn=new MyNode(5);
Node n=mn;
//java.lang.ClassCastException: java.lang.String cannot be cast to
java.lang.Integer
n.setData("Hello");
Integer x=mn.data;
System.out.println(x);
}
}We can go through Method.isBridge() Method to determine whether a method is a bridging method , In bytecode, the bridging method will be marked ACC_BRIDGE and ACC_SYNTHETIC, among ACC_BRIDGE It is used to explain that this method is a bridge method generated by compilation ,ACC_SYNTHETIC Note that this method is generated by the compiler , And will not appear in the source code . You can see jvm For these two access_flag The explanation of http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.6.
There are the following 3 A question :
- When will the bridge method be generated
- Why generate bridging methods
- How to get the actual method through the bridging method
a When will the compiler generate bridge methods ? You can see JLS Description in http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.12.4.5.
That is to say, a subclass inherits ( Or implementation ) A parent class ( Or interface ) When the generic method of , stay Generic types are explicitly specified in subclasses , Then the compiler will automatically generate the bridge method at compile time ( Of course, there are other situations that will generate bridging methods , Here is just one case ).
b Because generics at compile time, the compiler will check whether the type of the object added to the collection matches the generic type , If not, errors will be found during compilation , You don't have to wait until runtime to find errors . Because generics are in 1.5 Introduced , For forward compatibility , So generics will be removed at compile time ( Generic erase ), But we can still reflect API To get information about generics , At compile time, you can ensure the correctness of types through generics , You don't have to wait until runtime to find that the type is incorrect . because java Generic erasure feature , If no bridging method is generated , Then with 1.5 The previous bytecode is incompatible .
c When we make a method call through reflection , What if we get the actual method corresponding to the bridge method ? You can see spring in org.springframework.core.BridgeMethodResolver Class source code . In fact, it is by judging the method name 、 The number of parameters and generic type parameters .
Link to original :https://blog.csdn.net/mhmyqn/article/details/47342577
5.1.3 Heap pollution
Heap pollution( Heap pollution ), It refers to when assigning an object without generics to a variable with generics , Heap pollution may occur .
and Heap Pollution It may lead to more serious consequences : ClassCastException, We were just varagMethod Add a few lines of code to the method as follows :
public static void varagMethod(Set<Integer> objects) {
objects.add(new Integer(10));
}And then modify main Method :
public static void main(String[] args){
Set set = new TreeSet();
varagMethod(set);
Iterator<String> iter = set.iterator();
while (iter.hasNext())
{
String str = iter.next(); // ClassCastException thrown
System.out.println(str);
}
}

You can see , The program reported one ClassCastException( Type conversion error ), This is because Java Allow us to put a generic parameter free Set Object passed to varagMethod Method , And we are varagMethod In the method , To the incoming Set Object added a Integer object , Then we traverse set When the collection , take Set The first element in is strongly transformed into String, Obviously Integer Can't be converted into String object
5.2 Translate generic expressions
Pair<Parson> pair=new Pair<Parson>();
pair.getFirst();erase getFirst Will return... After the return type of Object type . The compiler automatically inserts Employee Cast of .
The compiler translates this method call into two virtual machine instructions :
- For the original method Pair.getFirst Call to .
- Will return Object Type cast to Parson type .
5.3 Subtype rule
5.3.1 Type boundary
Generic T In the end, it will be erased as Object type , Only use Object Methods .
5.3.2 wildcard
Unbounded wildcards
In the generic example above , We all specify specific types , At least also Object , Suppose there is a scenario , You don't know what this type is , It can be Object , It can also be Person To do that ? Wildcards are needed in this scenario , As shown below , Usually a To express
public void addAll(Collection<?> col){
...
}Upper bound wildcard
Based on the above scenario , I want to limit this type to Person Subclasses of , As long as it is Person All subclasses of can , If generics are written as <Person> Then you can only force the following , Then the meaning of generics is lost , Back to the original starting point .
In view of this situation, there is the introduction of bounded wildcards . Specifying the upper boundary in a generic type is called the upper boundary wildcard <? extends XXX>.

Upper bound wildcard , Not by itself ,

The upper bound is used for the input parameters of the method : The input subclass can


Add Subclass , Upper bound container , Can only get You can't add

Lower bound wildcard
The principle is the same as the upper bound wildcard , Lower bound Wildcards restrict unknown types to specific types or the type Of super type , Lower limit wildcards use wildcards (‘?’) Express , Heel super keyword , Lower limit of heel :<? super A> .

Empathy , Methods into the reference , The input parameter is a parent class, which can , only get No add
6 Limitations of generics
jdk Defined 7 Restrictions on the use of generic types :
1、 Generic instances cannot be instantiated with simple types
class Pair<K, V> {
private K key; private V value;
public Pair(K key, V value) {
this.key = key; this.value = value;
}
public static void main(String[] args) {
// Error will be reported at compile time , because int、char It belongs to the basic type , Cannot be used to instantiate generic objects
Pair<int,char> p = new Pair(8,'a');
// Compile without error
Pair<Integer,String> p2 = new Pair<>(8,"a");
} }2、 You cannot directly create type parameter instances
public static <E> void append(List<E> list) {
E elem = new E(); // compile-time error list.add(elem);
}
// As a solution , You can create by reflection
public static <E> void append(List<E> list, Class<E> cls) throws Exception {
E elem = cls.newInstance(); // OK
list.add(elem);
}3、 Cannot declare a static attribute as a generic type parameter
public class MobileDevice<T> {
// illegal
private static T os;
//...
}4、 Cannot use cast or instanceof
because java The compiler will do type erasure in the compiler , Therefore, the type of parameters cannot be verified at run time
public static <E> void rtti(List<E> list) {
// An exception will be prompted at compile time
if (list instanceof ArrayList<Integer>) {
// ...
}
}
The solution can be parameterized by unbounded wildcards
public static void rtti(List<?> list) {
// Compile without error
if (list instanceof ArrayList<?>) { // ... } }
In some cases , The compiler knows that type parameters are always valid , At this time, forced rotation is allowed
In some cases , The compiler knows that type parameters are always valid , At this time, forced rotation is allowed
List<String> l1 = ...;
ArrayList<String> l2 = (ArrayList<String>)l1; // OK5、 Cannot create array generics
6、 You can't create、catch、throw Parameterized type object
7、 Overloaded methods cannot have two methods of the same primitive type
7 Summary
7.1 Two dimensions :
- flag
- Inheritance
7.2 ArrayList in addAll Method
Upper bound wildcard , abstract list in addAll
public boolean addAll(Collection<? extends E> c) {
Object[] a = c.toArray();
int numNew = a.length;
ensureCapacityInternal(size + numNew); // Increments modCount
System.arraycopy(a, 0, elementData, size, numNew);
size += numNew;
return numNew != 0;
}
边栏推荐
- Invalid V-for traversal element style
- 3.MNIST数据集分类
- NTT template for Tourism
- A network composed of three convolution layers completes the image classification task of cifar10 data set
- Four digit nixie tube display multi digit timing
- Su embedded training - Day6
- Macro definition and multiple parameters
- STL -- common function replication of string class
- Semantic segmentation model base segmentation_ models_ Detailed introduction to pytorch
- String usage in C #
猜你喜欢

Design method and reference circuit of type C to hdmi+ PD + BB + usb3.1 hub (rj45/cf/tf/ sd/ multi port usb3.1 type-A) multifunctional expansion dock

Prediction of the victory or defeat of the League of heroes -- simple KFC Colonel

General configuration tooltip

What does interface testing test?

Chapter VIII integrated learning

12.RNN应用于手写数字识别

Chapter XI feature selection
![[note] common combined filter circuit](/img/2f/a8c2ef0d76dd7a45b50a64a928a9c8.png)
[note] common combined filter circuit

AI zhetianchuan ml novice decision tree

130. Zones environnantes
随机推荐
Chapter improvement of clock -- multi-purpose signal modulation generation system based on ambient optical signal detection and custom signal rules
Implementation of adjacency table of SQLite database storage directory structure 2-construction of directory tree
For the first time in China, three Tsinghua Yaoban undergraduates won the stoc best student thesis award
Su embedded training - Day8
[reprint] solve the problem that CONDA installs pytorch too slowly
Ag9311maq design 100W USB type C docking station data | ag9311maq is used for 100W USB type C to HDMI with PD fast charging +u3+sd/cf docking station scheme description
Using GPU to train network model
13. Enregistrement et chargement des modèles
2.非线性回归
Chapter IV decision tree
10. CNN applied to handwritten digit recognition
Micro rabbit gets a field of API interface JSON
14. Draw network model structure
Swift get URL parameters
Understanding of sidelobe cancellation
Semantic segmentation model base segmentation_ models_ Detailed introduction to pytorch
Authorization code of Axure rp9
Marubeni official website applet configuration tutorial is coming (with detailed steps)
A speed Limited large file transmission tool for every major network disk
10.CNN应用于手写数字识别