Consolidate one of the basics of JAVA-extensive explanation (1)
I. Introduction
1. What is generics? First, let us know that ArrayList is generics. What unexpected functions can ArrayList accomplish? Let's take a look at the following code:
ArrayList
strList = new ArrayList
();ArrayList
intList = new ArrayList
();ArrayList
doubleList = new ArrayList
();
You are familiar with ArrayList. Here we construct three lists containing String, Integer, and Double. This is what ArrayList is like: that is, various types of variables can be assembled into a corresponding List, instead of implementing an ArrayList class for each corresponding. I may not understand it here. It is always difficult to start with. Let's take a look at what we will do if there are no generics;
2. How can I read the following code without generics:
We implement two classes that can set the coordinate of points, respectively set the coordinate of point of Integer type and Float type:
// Set the Integer coordinate class IntegerPoint {private Integer x; // indicates the X coordinate private Integer y; // indicates the Y coordinate public void setX (Integer x) {this. x = x;} public void setY (Integer y) {this. y = y;} public Integer getX () {return this. x;} public Integer getY () {return this. y ;}}// set Float-type coordinate class FloatPoint {private Float x; // indicates X coordinate private Float y; // indicates Y coordinate public void setX (Float x) {this. x = x;} public void setY (Float y) {this. y = y;} public Float getX () {return this. x;} public Float getY () {return this. y ;}}
Now there is a problem: Have you found that they talked about different variable types? One is Integer and the other is Float, and there is no difference between others! Can we merge them into one?
The answer is yes, because both Integer and Float are derived from objects. We can use the following code instead:
class ObjectPoint{ private Object x ; private Object y ; public void setX(Object x){ this.x = x ; } public void setY(Object y){ this.y = y ; } public Object getX(){ return this.x ; } public Object getY(){ return this.y ; }}
That is, all objects are used to replace all subclasses;
The result is as follows:
ObjectPoint integerPoint = new ObjectPoint();integerPoint.setX(new Integer(100));Integer integerX=(Integer)integerPoint.getX();
When setting, use new Integer (100) to create an Integer.
integerPoint.setX(new Integer(100));
Then, force convert the value:
Integer integerX=(Integer)integerPoint.getX();
Since we set an Integer, there is no error in force conversion during the value.
Similarly, FloatPoint settings and values are similar. The Code is as follows:
ObjectPoint floatPoint = new ObjectPoint();floatPoint.setX(new Float(100.12f));Float floatX = (Float)floatPoint.getX();
But the problem arises: note that we use forced conversion here. Here we write very close to setX () and getX, so we clearly know that we are passing in the Float type. What if we remember wrong?
For example, if we change it to the following, Will an error be reported during compilation:
ObjectPoint floatPoint = new ObjectPoint();floatPoint.setX(new Float(100.12f));String floatX = (String)floatPoint.getX();
No !!! The key to our problem lies in this sentence:
String floatX = (String)floatPoint.getX();
Will an error occur during forced conversion. Because the compiler does not know what you pass in, and floatPoint. getX () returns the Object type, it is true to convert the Object into a String when compiling. No error will be reported.
At runtime, it is not. during runtime, The floatPoint instance explicitly transmits a Float type variable. If you want to convert it to a String type, the type conversion error is certainly reported!
Is there a way to merge the data into the same one in the compilation phase, and check whether the data type is correct during compilation? Of course, this is generic.
The following describes the generic writing and usage.
Ii. Definitions and usage of various generic types
1. Define and use generic classes. Let's first look at how generic classes are defined:
// Define the class Point
{// Here, you can write the identifier private T x; private T y; public void setX (T x) {// as the parameter this. x = x;} public void setY (T y) {this. y = y;} public T getX () {// return this as the return value. x;} public T getY () {return this. y ;}}; // IntegerPoint use Point
P = new Point
(); P. setX (new Integer (100); System. out. println (p. getX (); // FloatPoint use Point
P = new Point
(); P. setX (new Float (100.12f); System. out. println (p. getX ());
First, let's look at the running result:
We can see from the results that the effects of the IntegerPoint class and FloatPoint class are achieved in the beginning. Let's take a look at how generics are defined and used.
(1) define generic: Point
First, you can see the Point , That is, add a angle bracket behind the class name, which is an uppercase letter. T is written here. In fact, this letter can be any letter. Remember it here. It can be any capital letter with the same meaning.
(2) Use generics in the class
This T represents any class that derives the daily Object class, such as String, Integer, and Double. Note that T must be derived from the Object class. For convenience, you can use T as a String here, that is, how to use String in the class, then how can T be used in the class! So the following: defining variables as return values can be easily understood as definitions passed in as parameters.
// Define the variable private T x; // as the return value public T getX () {return x;} // as the public void setX (T x) {this. x = x ;}
(3) use generic classes
The usage of generic classes is as follows:
// Use IntegerPoint
P = new Point
(); P. setX (new Integer (100); System. out. println (p. getX (); // FloatPoint use Point
P = new Point
(); P. setX (new Float (100.12f); System. out. println (p. getX ());
First, construct an instance:
Point
p = new Point
() ;
The difference between this and the common constructor is that the common constructor is like this: Point p = new Point ();
The construction of generic classes must be added after the class name. , That is, a pair of angle brackets, with the type to be passed in the middle.
This is because the class Point is constructed like this: Therefore, you must add a type after the Point to define the meaning of T.
Then there is nothing special about getVar () and setVar (). You can call it directly.
From the above usage, we can clearly see the role of generics. When constructing a generic class instance:
// Use IntegerPoint
P = new Point
(); // FloatPoint use Point
P = new Point
();
T represents the type of T when you pass in the brackets. This is the biggest role of generics. We only need to consider logical implementation to use it for various types.
As we mentioned above, ArrayList is also a generic type, and its implementation is as follows:
public class ArrayList
{…………}
As you can see, it is the same as our Point implementation, which is the main reason why ArrayList can hold various types.
(4) Advantages of Using Generics
Compared with the method of using objects at the beginning, there are two advantages:
(1) do not use forced conversion
// Use the Object as the return value and convert it to the specified Float floatX = (Float) floatPoint. getX (); // when using generics, you do not need to forcibly convert them. Instead, StringSystem is used. out. println (p. getVar ());
(2) If the input type is incorrect during settVar (), an error will be reported during compilation.
We can see that the String type is used for construction, and when setVar is passed into the Integer type, an error is returned. Instead of reporting a forced conversion error at runtime, just like the Object implementation method.
2. Definitions of multiple generic variables and letter specifications
(1) Multi-generic variable definition
We have defined only one generic variable T. What if we need to transmit multiple generic variables?
You just need:
class MorePoint
{}
That is, separate the original T with commas and write any other uppercase letters. If you want to add a few, add a few. For example, if you want to add five generic variables, it should be like this:
class MorePoint
{}
For example, we add another field name on the Point, which is also expressed in generics. What should we do? The Code is as follows:
Class MorePoint
{Private T x; private T y; private U name; public void setX (T x) {this. x = x;} public T getX () {return this. x ;}............ Public void setName (U name) {this. name = name;} public U getName () {return this. name ;}// use MorePoint
MorePoint = new MorePoint
(); MorePoint. setName (harvic); Log. d (TAG, morPont. getName: + morePoint. getName ());
From the code above, we can see that the U usage of the newly added generic variable is the same as that of T.
(2) letter specifications
When defining generic classes, we have mentioned that the variables used to specify generics are uppercase letters:
class Point
{ …………}
Of course not !!!! Any letter is acceptable. They have the same meaning, but to improve readability, it is better to use Meaningful letters. Generally, the meanings of the letters used in different situations are as follows:
E-Element, which is often used in java Collection, such as List , Iterator , Set K, V-Key, Value, indicates the Map Key-Value Pair N-Number, Number T-Type, Type, such as String, Integer, etc. If these are not enough, take it as needed. There are 26 English letters.
Repeat it again. Which letter is meaningless! Only to improve readability !!!!
3. The definition and usage of generic interfaces define generics on interfaces. The Code is as follows:
Like the definition of generic classes, brackets are added after the class name;
(1) Method 1: Non-generic class
However, a problem occurs during use. Let's take a look at the following usage:
Class InfoImpl implements Info
{// Defines the subclass private String var of the generic interface; // defines the attribute public InfoImpl (String var) {// sets the attribute content through the constructor this. setVar (var) ;}@ Override public void setVar (String var) {this. var = var ;}@ Override public String getVar () {return this. var ;}} public class GenericsDemo24 {public void main (String arsg []) {InfoImpl I = new InfoImpl (harvic); System. out. println (I. getVar ());}};
First, let's first look at the definition of InfoImpl:
class InfoImpl implements Info
{ …………}
It should be clear that InfoImpl is not a generic class! Because the class name is not !
Then, here we set Info The generic variable T in is defined as the String type. Therefore, when setVar () and getVar () are rewritten, IDE will directly generate a String-type rewrite function.
At last, it is not difficult to use it. You can upload a String to construct an InfoImpl instance and then call its function.
public class GenericsDemo24{ public void main(String arsg[]){ InfoImpl i = new InfoImpl(harvic); System.out.println(i.getVar()) ; }};
(2) Method 2: Generic
In method 1, we directly set Info in the class The interface is filled, but our class can be constructed into a generic class. What if we use a generic class to construct a filled generic interface?
Interface Info
{// Define the generic public T getVar () on the interface; // define the abstract method. The return value of the abstract method is the generic type} class InfoImpl
Implements Info
{// Defines the subclass private T var of the generic interface; // defines the attribute public InfoImpl (T var) {// sets the attribute content through the constructor this. setVar (var);} public void setVar (T var) {this. var = var;} public T getVar () {return this. var ;}} public class GenericsDemo24 {public static void main (String arsg []) {InfoImpl
I = new InfoImpl
(Harvic); System. out. println (I. getVar ());}};
The most critical process is to construct a generic class:
Class InfoImpl
Implements Info
{// Defines the subclass private T var of the generic interface; // defines the attribute public InfoImpl (T var) {// sets the attribute content through the constructor this. setVar (var);} public void setVar (T var) {this. var = var;} public T getVar () {return this. var ;}}
In this class, we construct a generic class InfoImpl And then pass the generic variable T to Info. This indicates that both interfaces and generic classes use the same generic variable.
Then, the process of constructing a generic class instance remains the same.
public class GenericsDemo24{public static void main(String arsg[]){Info
i = new InfoImpl
(harvic);System.out.println(i.getVar()) ;}};
The role of using a generic class to inherit a generic interface is to allow users to define the variable types used by the interface, rather than writing them to the class like method 1.
Then we will make it easier to construct a class with multiple generic variables and inherit from the Info interface:
Class InfoImpl
Implements Info
{// Defines the subclass of the generic interface private U var; private T x; private K y; public InfoImpl (U var) {// sets the attribute content through the constructor this. setVar (var);} public void setVar (U var) {this. var = var;} public U getVar () {return this. var ;}}
In this example, we define three generic variables T, K, and U in the generic class and use the third generic variable U to fill the interface Info. In this example, the type of Info is determined by U.
The basic usage of generic classes is as follows:
public class GenericsDemo24{ public void main(String arsg[]){ InfoImpl
i = new InfoImpl
(harvic); System.out.println(i.getVar()) ; }}
4. Define and use generic functions
We have explained the generic usage of classes and interfaces. Let's talk about how to use generics in a single function. For example, we create a common StaticFans class and define two generic functions in it:
Public class StaticFans {// static function public static
Void StaticMethod (T a) {Log. d (harvic, StaticMethod: + a. toString ();} // common function public
Void OtherMethod (T a) {Log. d (harvic, OtherMethod: + a. toString ());}}
The above are the definition methods of static generic functions and general generic functions. The only difference with the previous method is to add To represent generic variables. There is no other difference.
The usage is as follows:
// Static method StaticFans. StaticMethod (adfdsa); // method 1 StaticFans.
StaticMethod (adfdsa); // method 2 // conventional method StaticFans staticFans = new StaticFans (); staticFans. OtherMethod (new Integer (123); // method 1 staticFans.
OtherMethod (new Integer (123); // method 2
The result is as follows:
First, let's look at the usage of static generic functions:
StaticFans. StaticMethod (adfdsa); // method 1 StaticFans.
StaticMethod (adfdsa); // method 2
From the results, we can see that the results of these two methods are exactly the same, but they have some differences, the differences are as follows:
Method 1: You can directly pass a value like a normal method. Any value can be (but must be of the type derived from the Object class, such as String or Integer ), the function internally identifies the current T category based on the passed parameters. But try not to use this implicit transfer method, and the code is not conducive to reading and maintenance. The reason is that you cannot call a generic function.
Method 2: Unlike method 1, To specify Value. If the value of the parameter is specified, all the T types used in the StaticMethod () function are forcibly specified as 'string. This is the recommended method.
Similarly, General generic functions can be used in either of the following ways:
StaticFans staticFans = new StaticFans (); staticFans. OtherMethod (new Integer (123); // method 1 staticFans.
OtherMethod (new Integer (123); // method 2
As you can see, as usual, first create a class instance and then call a generic function.
Method 1: The T type is implicitly passed. It is the same as above. We do not recommend this.
Method 2: Assign the value of T to the Integer type, so that the compiler reports an error if the parameter passed by OtherMethod (T a) is not an Integer.
Advanced: The returned value contains generics. In our function above, the return values are all void, but in reality it is impossible to all be void. Sometimes, we need to return generic variables, such as the following function:
public static
List
parseArray(String response,Class
object){ List
modelList = JSON.parseArray(response, object); return modelList;}
The Return Value of the function is List. Type. As for the input parameter Class The meaning of object. Here I want to tell you through this example that there is no difference between generic variables and the use of classes such as String, Integer, and Double. T is just a symbol and can represent String, integer, Double ...... The symbols of these classes, when using generic functions, directly view T as String, Integer, Double ...... Any one of them can write code. The only difference is that you must add Identifies generics;
5. other usage: Class Class transfer and Generic Array
(1) Use Class Passing generic Class objects Sometimes, we may encounter a situation, for example, when we use JSON to parse strings, the code is generally like this
public static List
parseArray(String response){ List
modelList = JSON.parseArray(response, SuccessModel.class); return modelList;}
SuccessModel is a custom parsing class. The Code is as follows. In fact, you don't have to worry about the definition of SuccessModel. Just consider the above Code. Writing SuccessModel code is not confusing. In fact, it is just the basic usage of fastJson.
The meaning of this Code is to parse the List according to SuccessModel .
public class SuccessModel { private boolean success; public boolean isSuccess() { return success; } public void setSuccess(boolean success) { this.success = success; }}
Now, how do we assemble the following sentence into a generic function?
public static List
parseArray(String response){ List
modelList = JSON.parseArray(response, SuccessModel.class); return modelList;}
First, we should extract SuccessModel separately as a generic variable, but how do we get SuccessModel. class used in parseArray?
Let's first look at the Code:
public static
List
parseArray(String response,Class
object){ List
modelList = JSON.parseArray(response, object); return modelList;}
Note that the Class we use Object To pass the class object of the class, that is, the SuccessModel. class we mentioned above.
This is because the Class It is also a generic type. It comes from class objects used to load classes. Its definition is as follows:
public final class Class
implements Serializable {…………}
Use Class The problem of loading generic Class objects is over. Let's take a look at the usage of generic arrays.
(2) define generic Arrays When writing a program, you may encounter a requirement similar to String [] list = new String [8];. here we can use a String array. Of course, we can also define a Generic Array, the Generic Array is defined as T [], which is consistent with String []. The usage is as follows:
// Define public static
T [] fun1 (T... arg) {// receives the variable parameter return arg; // returns a Generic Array} // uses public static void main (String args []) {Integer I [] = fun1 (1, 2, 3, 4, 5, 6); Integer [] result = fun1 (I );}
Let's first look at the definition code:
Public static
T [] fun1 (T... arg) {// receives the variable parameter return arg; // returns the Generic Array}
First, a static function is defined, and then the returned value is T []. The parameter is the variable length parameter of the received T type. If you do not know the usage of T... arg, you can find the JAVA variable length parameter.
Since the variable length parameter is input, it will be saved in the arg array, so we can directly return the array.
Now, this article is over. This article mainly describes the definition and usage of generics in various aspects. In the next article, we will describe it, knowledge about generic limitation and generic erasure during compilation.