当前位置:网站首页>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; // OK
5、 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;
}
边栏推荐
- A network composed of three convolution layers completes the image classification task of cifar10 data set
- 9.卷积神经网络介绍
- 2.非线性回归
- Fofa attack and defense challenge record
- Share a latex online editor | with latex common templates
- 2. Nonlinear regression
- Ag9310meq ag9310mfq angle two USB type C to HDMI audio and video data conversion function chips parameter difference and design circuit reference
- Leetcode notes No.7
- 10. CNN applied to handwritten digit recognition
- Taiwan Xinchuang sss1700 latest Chinese specification | sss1700 latest Chinese specification | sss1700datasheet Chinese explanation
猜你喜欢
Design method and application of ag9311maq and ag9311mcq in USB type-C docking station or converter
Prediction of the victory or defeat of the League of heroes -- simple KFC Colonel
8. Optimizer
完整的模型验证(测试,demo)套路
Four digit nixie tube display multi digit timing
Using GPU to train network model
Letcode43: string multiplication
Basic implementation of pie chart
Basic realization of line chart (II)
Complete model verification (test, demo) routine
随机推荐
串口接收一包数据
Macro definition and multiple parameters
String usage in C #
Vscode is added to the right-click function menu
Su embedded training - C language programming practice (implementation of address book)
130. 被圍繞的區域
Share a latex online editor | with latex common templates
C# ?,?.,?? .....
Cross modal semantic association alignment retrieval - image text matching
7. Regularization application
Leetcode notes No.21
Scheme selection and scheme design of multifunctional docking station for type C to VGA HDMI audio and video launched by ange in Taiwan | scheme selection and scheme explanation of usb-c to VGA HDMI c
Chapter improvement of clock -- multi-purpose signal modulation generation system based on ambient optical signal detection and custom signal rules
Su embedded training - Day7
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
NVIDIA Jetson test installation yolox process record
10.CNN应用于手写数字识别
Saving and reading of network model
6.Dropout应用
13. Model saving and loading