This article gives you the content is about the Java wildcard character detailed analysis (code), there is a certain reference value, the need for friends can refer to, I hope to help you.
The non-correlation of subtypes of generic types has been mentioned in the previous section of this article. But there are times when we want to be able to use generic types like normal types:
Styling a reference to a generic object
Sculpt a reference to a generic object
Styling a reference to a generic object
For example, suppose we have a lot of boxes with different fruits in each case, we need to find a way to deal with any one box of fruit in a generic manner. More generally, a is a subtype of B, and we need to find a way to assign an instance of the c<a> type to a c<b> type declaration.
In order to do this, we need to use an extension declaration with wildcards, as in the following example:
list<apple> apples = new arraylist<apple> (); list<? Extends fruit> fruits = apples;
“? Extends "is a subtype dependency of a generic type becomes reality: Apple is fruit subtype,list<apple> is list<? Extends subtype of fruit>.
Sculpt a reference to a generic object
Now let me introduce another wildcard character:? Super If Type B is a super type of type a (parent type), then c<b> is c<? Super a> subtypes:
list<fruit> fruits = new arraylist<fruit> (); list<? Super apple> = fruits;
Why does wildcard tagging work?
The principle is now clear: how do we use this new grammatical structure?
? Extends
Let's take a look at the second part of this example, which refers to the subtype dependency of the Java array:
Apple[] Apples = new apple[1]; fruit[] Fruits = apples;fruits[0] = new Strawberry ();
As we can see, when you add an strawberry object to an array of Apple objects declared as an fruit array, the code compiles, but throws an exception at run time.
Now we can use wildcards to convert the associated code into generics: Because Apple is a subclass of fruit, what do we use? Extends wildcard character, so that a List<apple> object definition can be assigned to a list< Extends Fruit> 's statement:
list<apple> apples = new arraylist<apple> (); list<? Extends fruit> fruits = apples;fruits.add (New strawberry ());
This time, the code will be compiled but gone! The Java compiler will prevent you from adding strawberry to a fruit list. We can detect errors at compile time and do not need to be checked at runtime to ensure that incompatible types are added to the list. Even if you add the fruit object to the list:
Fruits.add (New Fruit ());
You have no way of doing this. In fact, you can't go to a single use? Any value is written in the extends data structure.
The reason is very simple, you can think: this? The extends T wildcard tells the compiler that we are dealing with a subtype of type T, but we don't know what this subtype is. Because there is no way to be sure, we are not allowed to include any of this type of data in order to ensure type safety. On the other hand, because we know that no matter what type it is, it is always a subtype of type T, and when we read the data, we can ensure that the resulting data is an instance of type T:
Fruit get = fruits.get (0);
? Super
Use? What are the super wildcard characters generally? Let's take a look at this first:
list<fruit> fruits = new arraylist<fruit> (); list<? Super apple> = fruits;
We see fruits pointing to a list of some kind of super class (Supertype) with Apple. Again, we don't know what the super class is, but we know that Apple and any Apple subclass are compatible with its type. Since this unknown type is apple and is also a greenapple superclass, we can write:
Fruits.add (New Apple ()); Fruits.add (new Greenapple ());
If we want to add an apple superclass to it, the compiler warns you:
Fruits.add (New Fruit ()); Fruits.add (new Object ());
Because we do not know what kind of superclass it is, all such instances are not allowed to join.
What about getting data from this type of form? The result is that you can only take an object instance: because we don't know what the superclass really is, the only thing the compiler can guarantee is that it is an object, because object is a superclass of any Java type.
Access principles and PECS rules
Summarize? Extends and the? Super Wildcard features, we can draw the following conclusions:
If you want to get data from a data type, use the? Extends wildcard characters
If you want to write objects into a data structure, use the? Super wildcard characters
If you want to save and you want to take it, don't use a wildcard character.
This is the principle of access that Maurice Naftalin in his book Java Generics and collections, and the Joshua Rule Bloch effective in his book Pecs java.
Bloch reminded that this pecs refers to "Producer Extends, Consumer Super", this is more easy to remember and use.
The bottom of the above:
The Java Tutorial
Java generics and collections, by Maurice Naftalin and Philip Wadler
Effective Java Chinese version (2nd edition), by Joshua Bloch.
Despite all this wealth of information, sometimes I feel that a lot of programmers still don't quite understand the utility and meaning of Java generics. That's why I want to use one of the simplest forms to summarize the basic knowledge that programmers need to know about Java generics.
The motive of Java generics origin
The simplest way to understand Java generics is to think of it as a handy syntax that can save you from some Java-type conversions (casting):
list<apple> box = ...; Apple Apple = box.get (0);
The above code itself is clearly expressed: box is a list with Apple objects. The Get method returns an instance of an Apple object that does not require a type conversion. Without generics, the code above needs to be written like this:
List box = ...; Apple Apple = (apple) box.get (0);
Obviously, the main benefit of generics is that the compiler retains the type information for the parameter, performs type checking, and performs type conversion operations: The compiler guarantees the absolute correctness of these types of conversions.
Instead of relying on programmers to memorize object types, perform type conversions-which can cause a program to fail at runtime, difficult to debug and resolve-the compiler can help programmers to force a lot of type checking at compile time to find errors in them.
The composition of a generic type
The concept of a type variable is derived from the composition of the generic type. According to the Java language Specification, a type variable is an unrestricted identifier that arises in the following situations:
Generic-class declarations
Generic interface Declaration
Generic method declaration
Generic Constructor (constructor) declaration
Generic classes and Interfaces
If there is one or more type variables on a class or interface, it is generic. Type variables are defined by angle brackets and placed after the class or interface name:
Public interface list<t> extends collection<t> {...}
Simply put, a type variable plays a role like a parameter, which provides the compiler with the information to use for type checking.
Many classes in the Java class Library, such as the entire collection framework, have been modified in a generic format. For example, the list interface we used in the first section of the code above is a generic class. In that code, box is a list object, which is an instance of a class implementation with a list interface of an Apple type variable. The compiler uses this type variable parameter to automatically type-convert the Get method when it is called and returns an Apple object.
In fact, this new generic tag, or the Get method in the list interface, is this:
T get (int index);
The Get method actually returns an object of type T, and T is a type variable in the list<t> declaration.
Generic methods and constructors (Constructor)
Very similar, if one or more type variables are declared on the method and the constructor, they can also be generalized.
public static <t> T GetFirst (list<t> List)
This method will accept a parameter of type list<t> and return an object of type T.
Example
You can either use the generic classes provided in the Java class Library, or you can use your own generic classes.
Type-safe Write data ...
The following code is an example, we created a list<string> instance, and then loaded some data:
list<string> str = new arraylist<string> (); Str.add ("Hello"); Str.add ("World");
If we try to load another object in list<string>, the compiler will prompt an error:
Str.add (1); Cannot compile
Type-safe read data ...
When we use the List<string> object, it always guarantees that we get a String object:
String myString = str.get (0);
Traverse
Many classes in the class library, such as ITERATOR<T>, have been enhanced and have been generalized. The iterator () method in the List<t> interface now returns the Iterator<t>, and the object returned by its T next () method does not need to be cast again, and you get the correct type directly.
for (iterator<string> iter = Str.iterator (); Iter.hasnext ();) {String s = iter.next (); System.out.print (s);}
Using the Foreach
The "for each" syntax also benefits from generics. The preceding code can be written like this:
for (String s:str) {System.out.print (s);}
This is both easy to read and easy to maintain.
Automatic Encapsulation (autoboxing) and auto-unpacking (autounboxing)
When using Java generics, these two features of autoboxing/autounboxing are automatically used, just like this piece of code:
list<integer> ints = new arraylist<integer> () ints.add (0); Ints.add (1); int sum = 0; for (int i:ints) {su M + = i;}
However, one thing you have to understand is that encapsulation and decryption can lead to a loss of performance, all of which are used with caution.
Sub-type
In Java, like other languages with object-oriented types, the hierarchy of types can be designed like this:
In Java, a subtype of type T can be either an extension of type T or a direct or indirect implementation of type T (if T is an interface). Because "becoming a subtype of a type" is a transitive relationship, if Type A is a subtype of B and B is a subtype of C, then A is also a subtype of C. In the diagram above:
Fujiapple (Fuji Apple) is a subtype of apple
Apple is a sub-type of fruit (fruit)
Fujiapple (Fuji Apple) is a subtype of fruit (fruit)
All Java types are sub-types of type object.
Any subtype A of type B can be assigned to a declaration of type B:
Apple a = ...; Fruit f = A;
subtypes of generic types
If an instance of an Apple object can be assigned to a declaration of a Fruit object, as seen above, what is the relationship between,list<apple> and a list<fruit>? More general, if type A is a subtype of type B, what is the relationship between C<a> and c<b>?
The answer will surprise you: it doesn't matter. In more popular words, a generic type has no relation to whether it is a subtype.
This means that the following code is invalid:
List<apple> apples = ...; list<fruit> fruits = apples;
The following also does not allow:
List < Apple > apples; List < Fruit > fruits = ...; apples = fruits;
Why? An apple is a fruit, why can't a box of apples be a box of fruit?
In some things, this can be true, but not in the state and operation of the type (Class) encapsulation. What happens if a box of apples is treated like a box of fruit?
List<apple> apples = ...; list<fruit> fruits = Apples;fruits.add (New strawberry ());
If that's the case, we can put a variety of different fruit subtypes in the list, which is definitely not allowed.
Another way to get a more intuitive understanding: a box of fruit is not a box of apples, because it may be a box of another fruit, such as strawberry (subtype).
Is this a question to be aware of?
Should not be a big problem. The biggest reason programmers are surprised is the inconsistency of usages on arrays and generic types. For generic types, there is no relationship between them and the subtypes of the type. For arrays, they are related to subtypes: if Type A is a subtype of type B, then a[] is a subtype of b[]:
Apple[] apples = ...; fruit[] fruits = apples;
But wait a minute! If we put the problem exposed in the previous discussion, we can still add the Strawberrie (Strawberry) object to an array of Apple types:
Apple[] Apples = new apple[1]; fruit[] Fruits = apples;fruits[0] = new Strawberry ();
Such a portrait can be compiled, but throws a Arraystoreexception exception at run time. Because of this characteristic of the array, the Java runtime needs to check the compatibility of the types on the operations that store the data. This check, obviously, will bring some performance problems that you need to understand.
Again, generics are safer to use, and can "correct" flaws in Java arrays of this type.
Now that you're wondering why there's a relationship between this type and subtype on the array, I'll give you the answer to the book "Java Generics and collections": if they're irrelevant, you can't pass an array of objects of unknown type into a method (not encapsulated into object[each time), as in the following:
void sort (object[] o);
After generics appear, this personality of the array is no longer necessary to use (we'll talk about this in the next section), and we should actually avoid using