A few years ago when Java5 was not officially released, I saw some people write about new features in Tiger, and the first thing that hit me the most was generics (generics) and annotations (annotation), because they directly affected the grammatical habits of our coding.
In the subsequent use of the process, the generics have not been particularly in-depth use, did not encounter such requirements and scenarios. Just understand that generics in Java are compile-time, run-time is "wiped" out, and then there are a couple of wildcards that are sufficient.
Until one day I looked at the source code of the enum in Java5, and I found that it was so defined:
Java code
- Public abstract class Enum<e extends enum<e>> implements Comparable<e>, Serializable {
What does this enum<e extends enum<e>>, which is similar to recursive structure, mean?
Then I saw the Max method in the Collections tool class:
How can there be such a complex type of generic expression!?
(Fortunately, this situation is rare in our actual development process, and should not even be seen, probably only like the JDK in order to preserve the compatibility of the old version of the design of such a complex generic expression out.) )
Above the problem, you can get the answer by: Http://java.sun.com/j2se/1.5/pdf/generics-tutorial.pdf, the Chinese version in: http://blog.csdn.net/explorers/ Archive/2005/08/15/454837.aspx
The article in this generic guide is very detailed.
Perhaps you read the above article, still have doubts. What I'm following is some additions to this document (which will be a bit coincident with this document).
Before returning to the question I threw before:
Java code
- public static void Foo (LIST<? extends number> L) {
- L.add (New Integer (2)); Compile and pass? Why?
- }
- public static void Bar (LIST<? Super number> L) {
- L.add (New Integer (2)); Compile and pass? Why?
- L.add (New Float (2)); Ok?
- }
Here the main talk about < Extends t> and <? Super T> The use of these two wildcard characters for method parameters.
i.e. the PECS principle (Producser-extends, consumer-super) or the Get and Put principle
When a wildcard is not used, we define a method:
Java code
- public static <E> void Test (list<e> l) {
- E e = l.get (0);
- L.set (0, E);
- }
We have no problem with get and set from list because this e is of a certain type.
And when you use wildcards to describe parameters, it's a little different.
Let's define two wildcard characters first:
<? Extends E> is a wildcard character for Upper Bound (upper limit)
<? Super E> is a wildcard character for Lower Bound (lower limit)
1) When using Upper Bound to pass the match:
<?> is <? Shorthand for extends object>. (about <?> whether and < extends object> is completely equivalent, described at the end)
In eclipse, the error message is: The method set (int, capture#2-of.) in the type list<capture#2-of?> are not applicable for the Argum Ents (int, Object)
Note: <capture#2-of?> is a placeholder that represents the compiler's capture of wildcards, see more:
Http://www.ibm.com/developerworks/cn/java/j-jtp04298.html
The reason for set error is because the type in the method is not materialized (reified), you can pass a string,number,book, and so on any class that inherits from object as the parameter type of the list to the test method, The list requires that the type in the collection must be consistent, and there is no way to ensure that the set is in the same type as the list, for example, you pass the test method to the List<book> Then in the method set to enter an object obviously the type is inconsistent.
This is also the price at which the wildcard brings flexibility.
Conclusion: the use of < Extends e> such a wildcard character, the test method parameter list becomes only get cannot set (except NULL) or is not rigorous said it becomes read-only parameters, some similar to a producer, to provide data.
Java code
- 2) when using Lower Bound to pass the match:
- public static void Test (LIST<? Super Number> List) {
- Number n = list.get (0); Compile error
- Object o = list.get (0); Ok
- List.set (0, New Object ()); Compile error
- List.set (0, new Long (0)); Ok
- List.set (0, new Integer (0)); Ok
- }
The get can only get the most generalized parent type, that is, object.
When set, it must be a subclass of number or number.
The reason is similar to the above get.
Conclusion: the use of < Super E> This wildcard, the get of the test method parameter list is greatly restricted, only the most general way to get the data in the list, equivalent to get only the minimum level of access to the data (think you might have put in a book, But can only be accessed as object).
It is more suitable for set usage scenarios, like a consumer, primarily for consuming data.
The above is a description of the use of wildcards, the simple principle of pecs is the direct principle that guides us to use wildcard characters in generic methods. Parameters as a producer using <? Extends E> When using < as a consumer;? Super e>.
So, when we're done with the pecs principle, we'll go back and analyze how the two complex generic expressions are meant to be
1) class enum<e extends enum<e>>
It is indeed a "recursive type restriction" (Recursive type bound)
To understand this problem, we must first understand 2 points:
A) An enum can be understood as a set of limited data sets of the same type;
b) The data type requirement for the enum in Java must also be an enumeration type (that is, the enum class must be inherited).
For a) We first define a enum<t> that defines the type of T as its internal data type, so it looks like a normal collection.
Then the definition of type E according to B, requires that E must be inherited from Enum<t> <e extends enum<t>>
Actually E and T are one thing, they are the same type, so it's <e extends enum<e>>
Pause, maybe my above expression is not very reasonable may be fraught, recursive type restriction is some abstraction, it should have rigorous mathematical description, I do not know how to express, I first use another simple example to illustrate it
public static <t extends comparable<t>> T max (list<t> List)
This method is used to get the maximum value in the list, which defines a type expression for the <t extends comparable<t>>
This recursive type-constrained expression is easy to understand,
<t extends Comparable<t>> represents: For each type T that can be compared to itself.
Or, each implementation of the Comparable<t> interface type T, such as String implementation of the comparable<string>, Long implements the comparable<long> and so on
and enum because of the use of the enum keyword, let us ignore its underlying implementation is actually
Class Enumsample extends enum<enumsample> the fact that
For example, we define an enumeration such as Boundkind:
public enum boundkind{}
The compiler translates to:
Public final class Boundkind extends Java.lang.enum<boundkind>
See, this is similar to String implements Comparable<string> .
So we set back to <e extends enum<e>> is <boundkind extends enum<boundkind>>
This is good to understand, <e extends enum<e>> directly by the literal understanding: each inherited from the enum<e> type E, such as Boundkind inherited enum<boundkind>
By comparing with <t extends comparable<t>>, we can understand <e extends enum<e>>.
Now let's go back to the Max method in the Collections tool class:
Let's just simplify this expression and see
<t extends comparable<? Super t>> How do you understand that?
Since <t extends comparable<t>> we all understand, change the comparable<t> to
comparable<? Super t> is nothing to be puzzled about.
In the article "Java1.5 generics Tutorial", the explanation is:
T Accurate (exactly) and oneself can compare is not needed. What is required is that t be able to compare with one of its parent classes.
And in the second edition of Effictive Java, this is explained by the PECS principle:
The following is a modified declaration using a wildcard type:
In order to get the modified version from the initial declaration, to apply the pecs conversion two times, the most direct is to apply to the parameter list. It produces a T instance, so change the type from list<t> to List<? Extends T>. (OK good understanding)
。。。。。。
More flexible is the use of the type parameter T. Initially t is specified to extend Comparable<t>, but T's comparable consumes T instances (and produces an integer value that represents the order relationship). Therefore, the parameterized type comparable<t> is limited by the wildcard type comparable<? Super T> replaced. comparable is always a consumer, so use should always be comparable< Super t> takes precedence over comparable<t>.
The sentence of the blue bold is not good to translate. Let's take a look at the code to understand it:
Java code
- public static <t extends Comparable<? Super t>> T Max (collection<? extends t> Coll) {
- 1 iterator<? Extends t> i = Coll.iterator ();
- 2 T candidate = I.next ();
- 3 while (I.hasnext ()) {
- 4 T next = I.next ();
- 5 if (Next.compareto (candidate) > 0)//here Comparato
- 6 candidate = Next;
- 7}
- 8 return candidate;
- 9}
Line 5th, Bloch that Next.compareto (cand) is a consumption operation, in the consumption of a candidate object, according to the pecs principle, candidate type should use < Super t> to improve its flexibility.
I think Bloch will be the 5th line as a consumer operation is very awkward, I personally favor "Java1.5 generics Tutorial" in the explanation.
But in the final analysis, it is all about reducing the limit and improving the flexibility of comparison.
Finally, let's take a complete understanding:<t extends Object & comparable<? Super T>>
Just than <t extends comparable<? Super t>> has one more limit (bounds).
Object & comparable<? Super T> is a multi-qualified (multiple bounds) usage,
Syntax: T1 & T2 ... & Tn
A parameter of a type with multiple bounds is a subclass of the type listed in all bounds. When multiple bounds are used, the first type in the bounds is used as the erasure of the type parameter.
Finally, the return value of this method, according to the first qualification, wiped to the object type. This is because in previous versions this method was the object type that was returned and needed to be compatible.
(This sentence casually said, the validation found wrong, found that the type deduction is more complex, it is not to understand)
Because of the existence of the multi-qualification (multiple bounds), the corresponding increase in the generic method is a very elegant way of calling. Here's a piece of code to illustrate:
Java code
- public class Genericstest {
- Static class Book {};
- Static Class Storybook extends book implements comparable<storybook> {
- @Override
- public int compareTo (Storybook o) {
- return 0; Fixme
- }};
- Static class TechBook extends book implements comparable<techbook> {
- @Override
- public int compareTo (TechBook o) {
- return 0; Fixme
- }};
- public static <E> set<e> merge (set<? extends e> s1, set<? extends e> S2) {
- hashset<e> newset = new hashset<e> (S1);
- Newset.addall (S2);
- return newset;
- }
- public static void Main (string[] args) {
- hashset<storybook> S1 = new hashset<storybook> ();
- hashset<techbook> s2 = new hashset<techbook> ();
- set<book> sb = merge (S1, S2); Error
- You need to tell it which type to use by an explicit type parameter (explicit type parameter)
- set<book> bs = Genericstest.<book>merge (S1,S2); Ok
- Or
- set<comparable<?>> s = genericstest.<comparable<?>>merge (S1,S2);
- }
- }
The above direct call to merge (S1,S2) that line of code error prompt message:
Type Mismatch:cannot convert from set<genericstest.book&comparable<?>> to Set<genericstest.book >
This is attributed to the type derivation of generics (type inference), which requires an explicit description, such as the red Bold in the code above, when a definite type cannot be deduced.
Post-note:
Related to <?> and <? Whether extends object> is one thing
Today at noon found colleagues on the table on the fourth edition of the "Java Programming thought", conveniently turned over, found in the introduction of the generic chapter,
There is a description: "Unboundedwildcards.java shows the compiler to handle list<?> and list< Extends is different when object>. ”
It makes me wonder to look at its code, mainly because it is different from the warning message when the shape of the raw type is generic.
Will a raw arraylist modelling to list<?> no problem, but to list<? Extends Object> will have a warning.
Looked up on the internet, found that the <?> and <, extends object> is equivalent, there are some differences of opinion.
Http://mail.openjdk.java.net/pipermail/compiler-dev/2008-April/000316.html
http://bugs.sun.com/view_bug.do?bug_id=6559175
In this report, there are two pieces of code that reflect the difference:
Java code
- (1)
- public static void Main (string[] args) {
- Object customer = null;
- Foo ((list< extends string>) customer); [1]
- Foo ((list< extends object>) customer); [2] Compilation with warning
- Foo ((list<?>) customer); [3] compilation without warning
- }
- public static void Foo (list<?> List) {
- }
- (2)
- Object O2 = new list<?>[3]; Compile actually OK, estimated directly as raw processing
- Object O3 = new List<? Extends object>[3]; Error
The above two pieces of code, indicating that when with the raw type modeling when,<?> in the compiler processing method is indeed with < Extends object> is different, according to the scene it may be ignored by the compiler generic information and directly as raw type, and < Extends object> is not.
But this difference, some fastidious, in addition to the raw type conversion with differences, in terms of semantics can be considered to be completely equal,
See: http://bugs.sun.com/view_bug.do?bug_id=6480391
Unfortunately, JLS3 doesn ' t say they is equivalent.
Sun's developers replied:
? Should is considered equivalent to? Extends Object. I'll note this at the end of the text about bounds for wildcards in 4.5.1.
......
Hence, foo<?> is semantically equivalent to foo<? Extends object>
Java Generics mini-problem