Java generics and java generics
1. Overview
Before introducing the fan type, Java types include the original type and the complex type. The complex types include arrays and classes. After the fan type is introduced, a complex type
You can split it into more types in detail.
For example, the original type List is subdivided into more types, such as List <Object> and List <String>.
Note: List <Object> and List <String> are two different types,
There is no inheritance relationship between them, even if the String inherits the Object. The following code is invalid.
List <String> ls = new ArrayList <String> ();
List <Object> lo = ls;
The reason for this design is that, according to lo's declaration, the compiler allows you to add any object (such as Integer) To lo, but this object is
List <String> breaks the integrity of the data type.
Before introducing a model, to support multiple data types in methods in the class, you need to overload the method. After introducing the model, you can solve this problem.
(Polymorphism) to further define the relationship between multiple parameters and return values.
For example
Public void write (Integer I, Integer [] ia );
Public void write (Double d, Double [] da );
The specified model version is
Public <T> void write (T t, T [] ta );
2. Definition & Use
The naming style of type parameters is as follows:
We recommend that you use a concise name as the name of a formal parameter (if possible, a single character ). It is best to avoid lowercase letters, which makes it and other common
Parameters are easily separated.
T indicates the type, and no more specific type is used to distinguish it at any time. This is often seen in generic methods. If there are multiple types of parameters, we
It is possible to use T adjacent letters in the alphabet, such as S.
If a generic function appears in a generic class, it is best to avoid using the same name in the type parameters of the method and the type parameters of the class to avoid mixing
. The same is true for internal departments.
2.1 define a class with type parameters
When defining a class with a type parameter, you can specify the names of one or more types of parameters in the <> after the class is followed.
The value range is limited. multiple types of parameters are separated by commas.
After defining the type parameters, you can use the type parameters in almost any place (except static blocks, static attributes, and static methods) of the class after the definition position,
Just like using a common type.
Note: The type parameters defined by the parent class cannot be inherited by the quilt class.
Public class TestClassDefine <T, S extends T> {
....
}
2.2 define parameters to be type
When defining a method with a type parameter, specify the names of one or more types of parameters within <> after the visible range is modified (for example, public,
You can also define the value range of A type parameter. Multiple type parameters are separated by commas.
After defining a type parameter, you can use the type parameter anywhere in the method after the location is defined, just like using a common type.
For example:
Public <T, S extends T> T testGenericMethodDefine (T t, S s ){
...
}
Note: The main purpose of defining a method with a type parameter is to express the relationship between multiple parameters and return values. For example
The type of the returned value is the same as the value of the first type parameter.
If you only want to implement polymorphism, use wildcards first. For more information about wildcards, see the following section.
Public <T> void testGenericMethodDefine2 (List <T> s ){
...
}
Should be changed
Public void testGenericMethodDefine2 (List <?> S ){
...
}
3. Type parameter value assignment
When you assign values to type parameters of a class or method, you must assign values to all type parameters. Otherwise, a compilation error is returned.
3.1 assign a value to the type parameter of the class with the type parameter
You can assign a value to a class with a type parameter in either of the following ways:
When declaring a class variable or instantiating it. For example
List <String> list;
List = new ArrayList <String>;
When the second class is inherited or the interface is implemented. For example
Public class MyList <E> extends ArrayList <E> implements List <E> {...}
3.2 assign values to methods with type parameters
When the model method is called, the compiler automatically assigns a value to the type parameter. If the value cannot be assigned successfully, a compilation error is returned. For example
Public <T> T testGenericMethodDefine3 (T t, List <T> list ){
...
}
Public <T> T testGenericMethodDefine4 (List <T> list1, List <T> list2 ){
...
}
Number n = null;
Integer I = null;
Object o = null;
TestGenericMethodDefine (n, I); // T is Number, S is Integer
TestGenericMethodDefine (o, I); // T indicates the Object, and S indicates the Integer.
List <Number> list1 = null;
TestGenericMethodDefine3 (I, list1) // at this time, T is Number
List <Integer> list2 = null;
TestGenericMethodDefine4 (list1, list2) // compilation Error
3.3 wildcard characters
In the preceding two sections, assign a specific value to the type parameter. In addition, you can also assign an uncertain value to the type parameter. For example
List <?> UnknownList;
List <? Extends Number> unknownNumberList;
List <? Super Integer> unknownBaseLineIntgerList;
Note: In the Java Collection framework, for a container class whose parameter value is of an unknown type, only the elements in the class can be read,
Because its type is unknown, the compiler cannot identify whether the type of the element to be added is compatible with the type of the container. The only exception is NULL.
List <String> listString;
List <?> UnknownList2 = listString;
UnknownList = unknownList2;
ListString = unknownList; // compilation Error
4. array pattern
You can declare an array using a class with the specified parameter value, but cannot create an array.
List <Integer> [] iListArray;
New ArrayList <Integer> [10]; // compilation Error
5. Implementation Principle
5.1. Java model-based compiling technology does not contain the model information during runtime. Only the Class instance contains the definition information of the type parameter.
Generics are implemented through the front-end processing of the java compiler called erasure. You can (basically) Think of it as a Source
Code to source code conversion, which converts a generic version to a non-generic version.
Basically, erased removes all generic type information. All the type information between angle brackets is thrown away.
The List <String> type is converted to List. All references to type variables are replaced with the upper limit (usually Object) of type variables ). And,
No matter when the result code type is incorrect, a conversion to the appropriate type will be inserted.
<T> T badCast (T t, Object o ){
Return (T) o; // unchecked warning
}
Type parameters do not exist at runtime. This means that they do not add any time or space burden, which is good. Unfortunately, this also means
You cannot rely on them for type conversion.
. A generic class is shared by all its calls
What is the result of the following code?
List <String> l1 = new ArrayList <String> ();
List <Integer> l2 = new ArrayList <Integer> ();
System. out. println (l1.getClass () = l2.getClass ());
Maybe you would say false, but you're wrong. It prints true. Because all instances of a generic class have the same runtime class at runtime ),
Regardless of their actual type parameters.
In fact, generics are called generics because they have the same behavior for all their possible type parameters. The same class can be treated as many different
. As a result, static variables and methods of the class are also shared among all instances. This is why static methods or static initialization code
The reason is invalid.
5.3. Transformation and instanceof
Another implication that a generic class is shared by all its instances is that it makes no sense to check whether an instance is of a specific type.
Collection cs = new ArrayList <String> ();
If (cs instanceof Collection <String>) {...} // invalid
Similar to the following type conversion:
Collection <String> cstr = (Collection <String>) cs;
Get an unchecked warning, because the runtime environment does not perform such a check for you.
6. Class model processing
After Java 5, the Class becomes a model.
One change in JDK1.5 is that java. lang. Class is generic. This is an interesting example of extending generics to a container class.
Currently, Class has a type parameter T. You may ask, what does T represent? It represents the type of the Class Object. For example,
String. class indicates Class <String>, and Serializable. class indicates Class <Serializable>.
This can be used to improve the type security of your reflected code.
In particular, because the newInstance () method of Class returns a T, you can get a more precise type when using reflection to create an object.
For example, if you want to write a tool to query a database, give an SQL statement, and return a database that meets the query conditions.
Collection ).
One method is to explicitly pass a factory object, like the following code:
Interface Factory <T> {
Public T [] make ();
}
Public <T> Collection <T> select (Factory <T> factory, String statement ){
Collection <T> result = new ArrayList <T> ();
/* Run SQL query using jdbc */
For (int I = 0; I <10; I ++) {/* iterate over jdbc results */
T item = factory. make ();
/* Use reflection and set all of item's fields from SQL results */
Result. add (item );
}
Return result;
}
You can call:
Select (new Factory <EmpInfo> (){
Public EmpInfo make (){
Return new EmpInfo ();
}
}, "Selection string ");
You can also declare a class EmpInfoFactory to support the interface Factory:
Class EmpInfoFactory implements Factory <EmpInfo> {...
Public EmpInfo make () {return new EmpInfo ();}
}
Then call:
Select (getMyEmpInfoFactory (), "selection string ");
The disadvantage of this solution is that it requires one of the following two:
The lengthy anonymous factory class at the call, or declare a factory class for each type to be used and pass its object to the called place
This is not natural.
It is natural to use the class type parameter value, which can be reflected and used. Code without generics may be:
Collection emps = sqlUtility. select (EmpInfo. class, "select * from emps ");...
Public static Collection select (Class c, String sqlStatement ){
Collection result = new ArrayList ();
/* Run SQL query using jdbc */
For (/* iterate over jdbc results */){
Object item = c. newInstance ();
/* Use reflection and set all of item's fields from SQL results */
Result. add (item );
}
Return result;
}
However, this cannot return a set of exact types. Now the Class is generic. We can write:
Collection <EmpInfo> emps = sqlUtility. select (EmpInfo. class, "select * from emps ");...
Public static <T> Collection <T> select (Class <T> c, String sqlStatement ){
Collection <T> result = new ArrayList <T> ();
/* Run SQL query using jdbc */
For (/* iterate over jdbc results */){
T item = c. newInstance ();
/* Use reflection and set all of item's fields from SQL results */
Result. add (item );
}
Return result;
}
To obtain the set we want through a type of security.
This technique is a very useful technique and has become a widely used practice in new APIs for processing annotations.
7. New and Old Code compatibility
7.1. to ensure code compatibility, the following code compiler (javac) allows you to ensure type security.
List l = new ArrayList <String> ();
List <String> l = new ArrayList ();
7.2. When upgrading your class library to a standard version, use the covariant return value with caution.
For example
Public class Foo {
Public Foo create (){
Return new Foo ();
}
}
Public class Bar extends Foo {
Public Foo create (){
Return new Bar ();
}
}
Change Bar
Public class Bar extends Foo {
Public Bar create (){
Return new Bar ();
}
}
Be careful with the client of your class library.