1. Overview
Before generics were introduced, Java types were divided into primitive types, complex types, where complex types were divided into arrays and classes. After introducing the paradigm, a complex type
It can be broken down into more types.
For example, the original type List, which is now subdivided into list<object>, list<string> and so on more types.
Note that now List<object>, list<string> is two different types,
There is no inheritance between them, even if string inherits object. The following code is illegal
list<string> ls = new arraylist<string> ();
list<object> lo = ls;
The reason for this is that, depending on the LO declaration, the compiler allows you to add any object (such as an integer) to the lo, but this object is
List<string>, which destroys the integrity of the data type.
Before introducing generics, methods that need to be overloaded in a way that supports multiple data types in a method in a class can solve this problem after introducing the paradigm
(polymorphic), which further defines the relationship between multiple parameters and the return value.
For example
public void Write (Integer i, integer[] ia);
public void Write (Double D, double[] da);
The model version is
Public <T> void Write (T T, t[] ta);
2. Definition & Use
The naming style for type parameters is:
It is recommended that you use a concise name as the name of the formal type parameter (if possible, a single character). It's best to avoid lowercase letters, which makes it and other ordinary
The formal parameters are easily distinguishable.
Use T to represent a type, no matter when it is more specific than the type to differentiate it. This is often seen in generic methods. If there are more than one type parameter, we
It is possible to use the adjacent letters of T in the alphabet, such as S.
If a generic function appears inside a generic class, it is best to avoid using the same name in the type parameter of the method and the type parameter of the class to avoid mixing
Xiao The same is true for inner classes.
2.1 Defining a class with type parameters
When defining a class with a type parameter, specify the name of one or more type parameters in the <> immediately following the life of the class, and you can also take the parameters of the type
The value range is qualified, and multiple type parameters are separated by a number.
After you define the type parameters, you can use the type parameters almost anywhere in the class after you define the position (except static blocks, static properties, static methods),
It's like using a normal type.
Note that the type parameters defined by the parent class cannot be inherited by the quilt class.
public class testclassdefine<t, S extends t> {
....
}
2.2 Defining the type parameter method
When defining a method with a type parameter, specify the name of one or more type parameters in <>, immediately following the visible range decoration (for example, public).
You can also qualify the value range of the type parameter, separated by a number of type parameters.
After you define a type parameter, you can use the type parameter anywhere you define the method, just as you would with a normal type.
For example:
Public <t, S extends t> t Testgenericmethoddefine (T T, s s) {
...
}
Note: To define a method with a type parameter, the main purpose of the ride is to express the relationship between multiple parameters and the return value. For example, in the example of T and S, the following
The type of the return value is the same as the value of the first type parameter.
If you want to implement polymorphism only, use wildcard characters as a priority. The contents of the wildcard are shown in the following sections.
Public <T> void TestGenericMethodDefine2 (list<t> s) {
...
}
should read
public void TestGenericMethodDefine2 (LIST<? > s) {
...
}
3. Type parameter Assignment
When assigning a value to the type parameter of a class or method, all type parameters are required to be assigned values. Otherwise, you will get a compilation error.
3.1 Assigning a type parameter to a class with a type parameter
There are two ways to assign a type parameter to a class with a type parameter
The first declaration of a class variable or instantiation. For example
List<string> list;
List = new arraylist<string>;
The second inheriting class or when implementing an interface. For example
public class Mylist<e> extends arraylist<e> implements list<e> {...}
3.2 Assigning values to a band-type parameter method
When the generic method is called, the compiler automatically assigns a value to the type parameter when it cannot be successfully assigned to the Times compilation error. 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);//At this time t is number, S is integer
Testgenericmethoddefine (o, i);//t is object, S is integer
List<number> list1 = null;
TestGenericMethodDefine3 (i, list1)//At this time t is number
List<integer> list2 = null;
TestGenericMethodDefine4 (List1, List2)//Compile Error
3.3 wildcard characters
In the above two sections, the type parameter is given a specific value, and in addition to this, the type parameter can be given an indeterminate value. For example
List<?> unknownlist;
list<? Extends number> unknownnumberlist;
list<? Super Integer> Unknownbaselineintgerlist;
Note: In the Java Collection framework, for a container class with an unknown type for the parameter value, only the element can be read and cannot be added as an element.
Because the type is unknown, the compiler does not recognize that the type of the element being added and the type of the container is compatible, the only exception being null
List<string> liststring;
list<?> unknownList2 = liststring;
Unknownlist = UnknownList2;
liststring = unknownlist;//Compilation error
4. Array Paradigm
You can declare an array using a class with a generic parameter value, but you cannot create an array
List<integer>[] Ilistarray;
New arraylist<integer>[10];//compile-time error
5. Principle of implementation
5.1. Java paradigm When compile-time technology, does not contain the generic information at run time, only the class instance contains the type parameter definition information.
Generics are implemented through front-end processing of the Java compiler called erase (Erasure). You can (basically) think of it as a source
Code-to-source conversion, which converts the generic version to a non-generic version.
Basically, wiping out all the generic type information. All type information between the angle brackets is thrown away, so for example a
The list<string> type is converted to list. All references to type variables are replaced with the upper bound of the type variable (usually object). And
Whenever the result code type is incorrect, a conversion to the appropriate type is inserted.
<T> t Badcast (T T, Object O) {
Return (T) O; Unchecked warning
}
The type parameter does not exist at run time. This means that they do not add any time or space burden, which is good. Unfortunately, this also means
You can't rely on them for type conversions.
5.2. A generic class is shared by all its calls
What is the result of the following code printing?
list<string> L1 = new arraylist<string> ();
list<integer> L2 = new arraylist<integer> ();
System.out.println (l1.getclass () = = L2.getclass ());
Maybe you can say false, but you think wrong. It prints out true. Because all instances of a generic class have the same runtime class (class) at run time,
Regardless of their actual type parameters.
In fact, generics are called generics because they have the same behavior for all of their possible type parameters, and the same classes can be used as many different
of the type. As a result, the static variables and methods of a class are also shared among all instances. This is why the static or static initialization of the Code
It is not legal to use a type parameter (where the type parameter is a specific instance) in the Declaration and initialization of a static variable.
5.3. Transformation and instanceof
Another implication of the generic class being shared by all its instances (instances) is that it is meaningless to check whether an instance is a generic class of a particular type.
Collection cs = new arraylist<string> ();
if (CS instanceof collection<string>) {...}//illegal
Similarly, type conversions like the following
Collection<string> CStr = (collection<string>) CS;
Get a unchecked warning because the runtime environment does not check for you.
6. Class-based processing
After Java 5, class becomes generic.
A change in JDK1.5 is that the class Java.lang.Class is generic. This is an interesting example of extending generics beyond the container class.
Now that class has a type parameter T, you'll probably ask, what does t mean? It represents the type represented by the class object. For example
The String.class type represents class<string>,serializable.class on behalf of Class<serializable>.
This can be used to improve the type safety of your reflection code.
In particular, because the class's newinstance () method now returns a T, you can get a more precise type when you create an object with reflection.
For example, suppose you want to write a tool method for a database query, given an SQL statement, and return a database that meets the query criteria
Collection of Objects (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 the item ' s fields from SQL results */
Result.add (item);
}
return result;
}
You can call this:
Select (New Factory<empinfo> () {
Public Empinfo make () {
return new Empinfo ();
}
}, "Selection string");
You can also declare a class empinfofactory to support 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 either of the following:
Call the lengthy anonymous factory class, or declare a factory class for each type you want to use and pass its objects to the calling place
It's not natural.
Using the class type parameter value is very natural and can be used by reflection. Code that does not have generics might 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 the item ' s fields from SQL results */
Result.add (item);
}
return result;
}
But that doesn't give us a set of exact types we want to return. Now that 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 the item ' s fields from SQL results */
Result.add (item);
}
return result;
}
To get the collection we want in a type-safe way.
This technique is a very useful technique and it has become a customary usage that is widely used in the new API for processing annotations (annotations).
7. Old and new code compatible
7.1. In order to ensure the compatibility of the code, the following code compiler (JAVAC) allows, type safety has your own guarantee
List L = new arraylist<string> ();
list<string> L = new ArrayList ();
7.2. When upgrading your class library to a generic version, use the covariant return value sparingly.
For example, the code
public class Foo {
Public Foo Create () {
return new Foo ();
}
}
public class Bar extends Foo {
Public Foo Create () {
return new Bar ();
}
}
Use the covariant return value style to change the bar revision to
public class Bar extends Foo {
Public Bar Create () {
return new Bar ();
}
}
Be careful of the clients of your class library.
8. References
Http://java.sun.com/j2se/1.5/pdf/generics-tutorial.pdf
Java Generics tutorial