8 generic programming
8.1 Why use generic programming
- Type parameter (of the type the
E
Parameters) (T
, ,S
...) - Wildcard type (wildcard of the type)
?
( )
Note the use of both usefulness and different.
8.2 define simple generic class
public class Pair<T> {
private T first;
private T second;
public Pair() { first = null; second = null; }
public Pair(T first, T second) { this.first = first; this.second = second; }
public T getFirst() { return first; }
public T getSecond() { return second; }
public void setFirst(T newValue) { first = newValue; }
public void setSecond(T newValue) { second = newValue; }
}
8.3 generic method
Type variable modifier on the back, return to the previous type.
Generic methods can be defined in the general category, it can also be defined in generic classes.
When you call a generic method, into a specific type of angle brackets in front of the method name.
8.4 defining types of variables
By setting the variable T is defined type (bound):
public static <T extends Comparable> T min(T[] a) {. . .}
- Keyword is
extends
, T class and type may be defined, or may be an interface. - A variable type or wildcards may define a plurality of, for example:
T extends Comparable & Serializable
; type defined by '&' separated by commas to separate the variable type. - Defining most one class, and must be defined first in the list.
8.5 generic code and virtual machine
Virtual machine does generic type objects - all objects belong to the general category.
8.5.1 type erasure
Whenever you define a generic type, automatically provides a corresponding original type (raw type). Deleting the original type of the generic type name is the name of the type parameter. Erase (ERASED) type variable, and replaced defined type.
The first original type replaced with a variable type defined, if it is not replaced by defining the given Object. To improve efficiency, should the marker interface (i.e., interface with no methods) at the end of the boundary list.
public class Pair {
private Object first;
private Object second;
public Pair() { first = null; second = null; }
public Pair(Object first, Object second) { this.first = first; this.second = second; }
public Object getFirst() { return first; }
public Object getSecond() { return second; }
public void setFirst(Object newValue) { first = newValue; }
public void setSecond(Object newValue) { second = newValue; }
}
8.5.2 Translation generic expression
When a program calls a generic method, if the return type erase, the compiler inserts cast.
8.5.3 Translation generic method
If the polymorphic type erasure clashed, for example:
public class Datelnterval extends Pair<LocalDate> {
@Override
public void setSecond(LocalDate second) {
if (second.compareTo(getFirst()) >= 0)
super.setSecond(second);
}
...
}
After type erasure, become:
class DateInterval extends Pair {
public void setSecond(LocalDate second) { . . . }
. . .
}
But after the Pair type erasure method is
public void setSecond(Object second);
When the coating method parameters is inconsistent with this polymorphism had a conflict. Therefore, the compiler generates is Datelnterval 桥方法
(Bridge Method,):
public void setSecond(Object second) { setSecond((LocalDate) second); }
If the bridge generation method get method, so in Datelnterval class, there are two methods getSecond:
LocalDate getSecond() // defined in DateInterval 中定义的
Object getSecond() // 桥方法,覆盖 Pair 中的方法,调用第一个方法
Method signature (the return value does not include) the same two methods are not legal.
However, in a virtual machine, the type of parameter and return type determining method. Thus, the compiler may generate return only two different types of methods byte code, the virtual machine to handle the situation correctly.
The fifth chapter mentioned covariant return types also use the bridge method
In short, to remember facts about the conversion of Java generics:
- Virtual machine without generics, only ordinary classes and methods.
- All types of parameters are defined by their type of replacement.
- Bridge methods are synthesized to keep the polymorphism.
- In order to maintain the type of security, if necessary, insert cast.
8.5.4 call legacy code (abbreviated)
8.6 Restrictions and limitations
8.6.1 base type can not be used to instantiate type parameter
No Pair<double>
, only Pair<Double>
. Because after type erasure, Pair would Object domain, and Object can not be stored double.
8.6.2 runtime type queries only applies to the original type
Such as:
if (a instanceof Pair<String>) // Error
if (a instanceof Pair<T>) // Error
Pair<String> p = (Pair<String>) a; // Warning--can only test that a is a Pair
In fact, only tests whether a is a Pair. When reminded of the risks, try to check whether an object belongs to a generic type, if using instanceof will get a compiler error, if the cast will get a warning. Similarly, the getClass
method always returns the original type. Because the total virtual machine object has a specific non-generic types.
8.6.3 You can not create arrays of parameterized types
Such as:
Pair<String>[] table = new Pair<String>[10]; // Error
Object[] objarray = table;
objarray[0] = "Hello"; // Error--component type is Pair
objarray[0] = new Pair<Employee>(); // 可以通过数组存储检査
Therefore not allowed to create (new) parameterized type of array. But the statement is legitimate and can be initialized using the type conversion.
Pair<String>[] table = (Pair<String>[]) new Pair<?>[10];
Of course it's safe. Only a safe and effective method: ArrayList<Pair<String>>
.
8.6.4 Varargs warning
Method variable number of parameters:
public static <T> void addAll(Collection<T> coll, T... ts)
{
for (t : ts) coll.add(t);
}
// 如下调用:
Collection<Pair<String>> table = . . .;
Pair<String> pair1 = . . .;
Pair<String> pair2 = . . .;
addAll(table, pair1, pair2);
To call this method the opportunity to create a virtual Pair<String>
array. But this time will only get a warning rather than an error. Eliminate this warning can be annotated @SuppressWarnings("unchecked")
or @SafeVarargs
.
8.6.5 Examples of types becomes not opposed
You can not use new T(...)
or T.class
such expressions.
Want to create an instance of the caller can provide a constructor expression or provide class (then Class.newlnstance method).
// 1.构造器表达式
Pair<String> p = Pair.makePair(String::new);
public static <T> Pair<T> makePair(Supplier<T> constr)
{
return new Pair<>(constr.get(), constr.get());
}
// 2. 提供class
Pair<String> p = Pair.makePair(String.class);
public static <T> Pair<T> makePair(Class<T> cl)
{
try { return new Pair<>(cl.newInstance(), cl.newInstance()); }
catch (Exception ex) { return null; }
}
8.6.6 can not be constructed generic array
Can not new T[...]
.
- Expressions or a reflective configuration, see P324
ArrayList.toArray
Examples, see P324
8.6.7 Static context generic class type variable invalid
You can not reference type variable domain or in a static method.
public class Singleton<T> {
private static T singleInstance; // Error
public static T getSingleInstance() // Error
{
if (singleInstance == null) construct new instance of T
return singleInstance;
}
}
Statement Singleton<Random>
and Singleton<JFileChooser>
, but only after type erasure Singleton class, it has only one singleInstance domain.
8.6.8 can not throw or capture instance generic class
Neither throw nor capture a generic class object. In fact, even the generic class extends Throwable is illegal.
public class Problem<T> extends Exception { /* . . . */ } // Error--can't extend Throwable
catch clause can not use the type variable:
public static <T extends Throwable> void doWork(Class<T> t) {
try {
do work
}
catch (T e) { // Error--can't catch type variable
Logger.global.info(...)
}
}
However, the use of variable type specification exception is permitted.
public static <T extends Throwable> void doWork(T t) throws T { // OK
try {
do work
}
catch (Throwable realCause) {
t.initCause(realCause);
throw t;
}
}
8.6.9 can eliminate the inspection of checked exception of
8.6.10 attention to post-conflict erased
8.7 generic types of inheritance rules
-
Whether S have any contact with the T, generally,
Pair<S>
withPair<T>
no connection. -
You can always convert a parameterized type is a primitive type. But there are risks, such as:
Pair<Manager> managerBuddies = new Pair<>(ceo, cfo);
Pair rawBuddies = managerBuddies; // OK
rawBuddies.setFirst(new File(". . .")); // only a compile-time warning
Manager one = rawBuddies.getFirst(); // 抛出 ClassCastException 异常
- Generic class can extend or implement other generic classes. , There is no difference between ordinary classes this regard.
For example,ArrayList<T>
class implementsList<T>
the interface. This means that aArrayList<Manager>
can be converted into oneList<Manager>
. However, as seen before, aArrayList<Manager>
is not aArrayList<Employee>
orList<Employee>
.
8.8 wildcard type
8.8.1 Wildcard concept
Wildcard type, allowing the change type parameter. E.g:
Pair<? extends Employee>
It is the type parameter is any subclass of Employee Pair generic type.
Pair<Employee>
And Pair<Manager>
all Pair<? extends Employee>
sub-types.
Use wildcard by Pair<? extends Employee>
reference will not damage Pair<Manager>
:
Pair<Manager> managerBuddies = new Pair<>(ceo, cfo);
Pair<? extends Employee> wildcardBuddies = managerBuddies; // OK
wildcardBuddies.setFirst(lowlyEmployee); // compile-time error
Because Pair<? extends Employee>
the method looks like this:
? extends Employee getFirst()
void setFirst(? extends Employee)
This will not be possible to call setFirst method. The compiler needs to know only one subtype of Employee, but do not know
specifically what type. It is transmitted to any particular type of refuse. After all, ?
it can not be used for matching.
Use getFirst problem does not exist: the getFirst the return value is assigned to an Employee reference perfectly legal.
This is where there is limited wildcard key point: now there is a way to distinguish between a safe 访问器
method and unsafe 更改器
way to go.
8.8.2 wildcard defining supertype
通配符限定
And 类型变量限定
it is very similar, but it can also specify a type of super-limited (supertype bound).
For example, Pair<? super Manager>
there are methods:
void setFirst(? super Manager)
? super Manager getFirst()
The compiler can not know the specific type setFirst method, and therefore can not accept the argument of type Employee or Object when calling this method. Object Manager can only pass type, or a sub-type of the object.
In addition, if you call getFirst, we can not guarantee the return type of the object, can only assign it to a Object.
Intuitively, wildcards with supertype may be written to define a generic object with wildcard subtype defined it can be read from the generic object.
8.8.3 indefinite wildcard
Such Pair<?>
as: .
? getFirst()
void setFirst(?)
getFirst return value can only be assigned to an Object. setFirst method can not be called, even passing Object object (it can be called setFirst(null)
). However, it may be passed into the original type Pair setFirst method of any Object object.
- Use simple operations that readability stronger. The detection of a pair contains a null reference:
public static boolean hasNulls(Pair<?> p)
{
return p.getFirst() == null || p.getSecond() == null;
}
8.8.4 Wildcard capture
public static void swap(Pair<?> p) {
swapHelper(p);
}
public static <T> void swapHelper(Pair<T> p) {
T t = p.getFirst();
p.setFirst(p.getSecond());
p.setSecond(t);
}
Note: swapHelper is a generic method, swap rather than having a fixed Pair<?>
type parameter.
In this case, swapHelper capture wildcard parameter T method. It is not known what type the wildcard representation, but it is a certain type.
8.9 reflection and generics
Class class is generic. For example, String.class
in fact, an Class<String>
object class (in fact, is the only object).
Erased classes still retained some generic information about their origin:
public static Comparable min(Comparable[] a)
is erased by a generic method:
public static <T extends Comparable<? super T>> T min(T[] a)
You can use the reflection API to determine:
- The generic method has a type parameter called T's.
- This parameter has a subtype of the type defined, which is itself a generic type. //
Comparable<? super T>
- This defines the type of parameter has a wildcard. //
? super T
- This parameter has a wildcard defining supertype.
- The generic method has a generic array parameter. //
T[] a
In other words, you can reconstruct all the information about generic classes and methods, as they realize that those statements. But you do not know the specific object or method call is how to deal with the type of the parameter.
To express the generic type declaration, using java.lang.reflect
the interface provided in the packet Type
. This interface contains the following subtypes:
Class
Class, a specific type.Type Variable
Interface described type variable (e.g.,T extends Comparable<? super T>
).WildcardType
Interface described wildcards (e.g.,?super T
).ParameterizedType
Interfaces, generic description of a class or interface type (e.g.,Comparable<? super T>
).GenericArrayType
Interfaces, generic description array (e.g.,T[]
).
Said section to see the truth behind the wild card and foggy. . . . .