The logic of the computer program (36)-Generics (middle)-Resolving wildcard characters

Source: Internet
Author: User
Tags addall comparable

The basic concepts and principles of generics are described in the previous section, and this section continues the discussion of generics, mainly on the concept of wildcard characters in generics. Wildcards have confusing and confusing syntax, but wildcard characters are heavily used in Java container classes, what exactly is it? In this section, let's step through the analysis.

More Concise parameter type qualification

At the end of the previous section, we mentioned an example, in order to add an integer object to the number container, our type parameter uses the other type parameter as the upper bound, the code is:

 Public extends void AddAll (dynamicarray<t> c) {    for (int i=0; i<c.size;i++) {        Add (c.get (i));}    }

We mentioned that this is a bit verbose, and it can be replaced with a more concise wildcard form:

 Public void extends E> c) {    for (int i=0; i<c.size; i++) {        Add (c.get (i));}    } 

This method does not define a type parameter, the type of C is dynamicarray<? Extends E>,? means wildcard, <? Extends e> indicates that there is a qualified wildcard character that matches a subtype of E or E, specifically what subtype we do not know.

The code that uses this method does not need to make any changes, or it can be:

New Dynamicarray<>();D ynamicarraynew dynamicarray<>(); Ints.add (+); Ints.add (numbers.addall); (ints);

Here, E is the number type, dynamicarray< Extends e> can match dynamicarray<integer>.

<t extends e> and <? Extends e>

So the problem comes, the same extends keyword, the same applies to generics, <t extends e> and < What does extends e> really matter?

They do not use the same place , we explain:

    • <t extends e> is used to define a type parameter , which declares a type parameter T, which can be placed after the class name in the generic class definition, before the generic method return value.
    • <? Extends e> is used to instantiate a type parameter , which is used to instantiate a type parameter in a generic variable, except that the specific type is unknown and only knows that it is a subtype of E or E.

Although they are different, the two formulations can often achieve the same goal , for example, in the previous example, the following two ways can be:

 Public void extends E> c)publicextendsvoid

So, what kind of form should we use? Let's begin by understanding the wildcard character and then explaining it.

Understanding wildcard Characters

Unqualified wildcard characters

There is also a wildcard, shaped like dynamicarray<?>, called unqualified wildcard , let's take a look at the example used to find the specified element in Dynamicarray, the code is as follows:

 Public Static int indexOf (dynamicarray<?> arr, Object Elm) {    for(int i=0; i< Arr.size (); i++) {        if(Arr.get (i). Equals (Elm)) {            return  i;        }    }     return -1;}

In fact, this unqualified wildcard form can also be used instead of the type parameter. In other words, the following wording:

 Public Static int indexOf (dynamicarray<?> arr, Object Elm)

Can be changed to:

 Public Static int indexOf (dynamicarray<t> arr, Object Elm)

However, the wildcard form is more concise.

Read-only character of wildcards

Wildcard form is more concise, but the above two wildcard characters have an important limit, can only read, can not write.

How do you understand it? Look at the following example:

New Dynamicarray<>();D ynamicarrayextends number> numbers =; Numbers.add (a); Numbers.add ((number) a); Numbers.add ((Object) a) ;

Three kinds of add methods are illegal, either integer or number or object, the compiler will error. Why is it?

? is the expression of type safety ignorance? Extends number represents a subtype of number, but does not know the specific subtype, and if write is allowed, Java cannot ensure type safety, so it is forbidden altogether. Let's look at an example to see what happens if a write is allowed:

New Dynamicarray<>();D ynamicarrayextends number> numbers =new Double (23.0  New String ("Hello World"); Numbers.add (n); Numbers.add (o) ;

If the object or number type is allowed to be written, the last two lines of compilation are correct, that is, Java will allow double or string objects to be placed in an integer container, which clearly violates Java's commitment to type safety.

In most cases, this limitation is good, but it makes it impossible for some of the basic operations that are supposed to be correct, such as swapping the positions of two elements to see the code:

 Public Static void int int j) {    = arr.get (i);    Arr.set (I, Arr.get (j));    Arr.set (J, TMP);}

This code should look correct, but Java will prompt for compilation errors, and both lines of SET statements are illegal. However, with the use of generic methods with type parameters, this problem can be resolved as follows:

Private Static void int int j) {    = arr.get (i);    Arr.set (I, Arr.get (j));    Arr.set (J, TMP);}  Public Static void int int j) {    swapinternal (arr, I, j);}

Swap can call swapinternal, and swapinternal with the type parameter can write. There are similar usages in Java container classes where the common API is a wildcard form and is simpler in form, but internally calls a method with a type parameter.

Dependency between parameter types

In addition to this need to write, if there is a dependency between the parameter types, you can only use the type parameter, for example, look at the following code, copy the contents of the SRC container into the dest:

 Public Static extends void Copy (dynamicarray<d> dest,        dynamicarray<S> src) {    for (int i=0; i<src.size (); i++) {        Dest.add (Src.get (i));}    }

S and d have dependencies, either the same, or S is a subclass of D, otherwise the type is incompatible and there is a compilation error. However, the above declaration can be simplified with a wildcard character, and two parameters can be simplified to one, as follows:

 Public Static void Copy (dynamicarray<d> dest,        dynamicarrayextends d> src) {      for (int i=0; i<src.size (); i++) {        Dest.add (Src.get (i));}    }

Wildcard characters and return values

Also, if the return value depends on the type parameter, you cannot use a wildcard character, for example, to calculate the maximum value in a dynamic array, as follows:

 Public Static extends Comparable<t>> T Max (dynamicarray<t> arr) {    = arr.get (0);      for (int i=1; i<arr.size (); i++) {        if(Arr.get (i). CompareTo (max) >0) {            = Arr.get (i);        }    }     return Max;}

The above code is difficult to replace with wildcard characters.

wildcard character or type parameter?

Now let's see if the generic method should be in the form of a wildcard or an add-on type parameter? What is the relationship between the two? We summarize below:

    • Wildcard forms can be substituted by the form of the type parameter, the wildcard can do, with the type parameter can do.
    • Wildcard form can reduce the type parameter, the form is often more simple, readability is also better, so, you can use wildcards with wildcard characters.
    • If there is a dependency between the type parameters, or if the return value depends on the type parameter, or if a write operation is required, only the type parameter is used.
    • Wildcard forms and type parameters are often used in conjunction with, for example, the copy method above, defining the necessary type parameters, using wildcards to express dependencies, and accepting a wider range of data types.

Super-type wildcard characters

Flexible writing

There is also a wildcard character, with the form < Extends e> just the opposite, it's in the form of < Super E>, called a super-type wildcard , represents a parent type of E, what's the use of it? with it, we can write more flexibly.

Without this syntax, there are some limitations to writing, and for example, let's add a method to Dynamicarray:

 Public void copyTo (dynamicarray<e> dest) {    for (int i=0; i<size;i++) {        Dest.add (Get (i));}    }

This method is also very simple, adding elements from the current container to the incoming target container. We may want to use this:

New Dynamicarray<integer>(), Ints.add (ints.add);D ynamicarrayNew dynamicarray<number>(); Ints.copyto (numbers);

An integer is a subclass of number, and it should be reasonable to copy the integer object into the number container, but Java will prompt for a compilation error, as we have said before, the expected parameter type is Dynamicarray<integer >,DynamicArray<Number> does not apply.

As previously mentioned, Dynamicarray<integer> cannot be seen as dynamicarray<number> in general, but our usage here is no problem, and Java's approach to solving this problem is the super-type wildcard character, You can change the CopyTo code to:

 Public void Super E> dest) {    for (int i=0; i<size; i++) {        Dest.add (get (i));}    } 

In this way, there is no problem.

Flexible comparison

Super-type Wildcard Another common occasion is the Comparable/comparator interface. Again, let's take a look at what's the limit if you don't use it. As an example of a method that calculates the maximum value previously, its method declaration is:

 Public Static extends Comparable<t>> T Max (dynamicarray<t> arr)

What are the restrictions on this statement? For a simple example, there are two classes of base and Child,base code:

classBaseImplementsComparable<base>{    Private intSortOrder;  PublicBase (intSortOrder) {         This. SortOrder =SortOrder; } @Override Public intcompareTo (Base o) {if(SortOrder <O.sortorder) {            return-1; }Else if(SortOrder >O.sortorder) {            return1; }Else{            return0; }    }}

The base code is simple and implements the comparable interface, which is compared against the instance variable sortorder. The child code is:

class extends Base {    public child (int  sortOrder) {         Super(SortOrder) ;    }}

Here, child is very simple, just inherit the base. Note that child does not re-implement the comparable interface because the child's comparison rules and base are the same. We might want to use the previous Max method to manipulate the child container as follows:

New Dynamicarray<child>(); Childs.add (new Child), Childs.add (new Child ( += max (childs);

Unfortunately, Java will prompt for compilation errors and type mismatches. Why doesn't it match? We might think that Java infers the type parameter T of the Max method to be a child type, but the requirement of type T is extends Comparable<t>, while child does not implement COMPARABLE<CHILD> It implements the comparable<base>.

But our requirements are reasonable, and the base class code already has all the data needed for comparison, and it should be able to be used to compare child objects. The way to solve this problem is to modify the method declaration of Max, using the super-type wildcard character, as follows:

 Public Static extends Super T>> T Max (dynamicarray<t> arr)

Just modify it, you can, this way of writing is more abstract, replace T with Child, that is:

extends Super Child>

<? Super Child> can match base, so the whole is a match.

No <t Super e>

We compare the type parameter qualification with the superclass wildcard, the type parameter is limited to extends form, there is no super form, for example, the preceding CopyTo method, its wildcard form declaration is:

 Public void Super E> dest)

If the type parameter qualification supports super form, it should be:

 Public Super void copyTo (dynamicarray<t> dest)

The fact is that Java does not support this syntax.

As we said earlier, for a qualified wildcard form < Extends E> You can qualify overrides with type parameters, but you cannot replace them with type parameters for super-type wildcard characters like the above.

Wildcard comparison

Two kinds of wildcard characters form <? Super e> and <? Extends e> is also relatively easy to confuse, we will compare.

    • Their purpose is to make the method interfaces more flexible and to accept a wider range of types.
    • < Super e> is used for flexible writes or comparisons so that objects can be written to a container of the parent type, so that the comparison method of the parent type can be applied to the child class object.
    • < extends e> is used for flexible reading , allowing the method to read the container object of any subtype E or E.

In the implementation of the Java container class, there are many such usages, for example, the following methods in collections:

 Public Static<textendscomparable<?SuperT>>voidSort (list<t>list) Public Static<T>voidSort (list<t> List, comparator<?SuperT>c) Public Static<T>voidCopy (LIST&LT;?SuperT> dest, list<?extendsT>src) Public Static<T> T Max (collection<?extendsT> Coll, comparator<?SuperT> comp)

Through the previous section and this section, we should be able to understand the meaning of these method declarations.

Summary

This section describes the three types of wildcard characters in generics,<?>, < Extends e> and <? Super E>, and analyzes the differences and relations with the type Parameter form.

In short, it concludes:

    • <?> and <? The extends e> is used for more flexible reads, which can be substituted as type parameters, but the wildcard form is more concise.
    • <? The super e> is used for more flexible writes and comparisons, and cannot be substituted for type parameter forms.

There are some details and limitations about generics, so let's go on to the next section.

----------------

To be continued, check out the latest articles, please pay attention to the public number "old Horse Programming" (Scan the QR code below), from the introduction to advanced, in layman's words, Lao Ma and you explore the nature of Java programming and computer technology. Write attentively, original articles, and keep all copyrights.

The logic of the computer program (36)-Generics (middle)-Resolving wildcard characters

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.