Java wildcard characters in generics

1 upper bounds wildcards

First of all, you need to know that the array in the Java language pays covariance. What does that mean? Look at the code below:

Static class A extends Base{void (f) {System.out.println ("A.f");}} static class B extends A (f) {void {System.out.println ("B.f");}} static class C extends B (f) {void {System.out.println ("C.f");}} static {A[] = arrayA new A[3]; arrayA[0] = new; arrayA[1] = (A) new (B); arrayA[2] = new (C); for (A item arrayA) {}}); item.f (//output A.f B.f C.f

We obviously let the array type be A, but adding B and C to it is also possible. Why? We found that B inherits from A, which belongs to the subclass of A, C inherits B, belongs to the subclass of B inheritance in the Java can be passed, so C still belongs to a subclass of A, so B and C are a subclass of A, another point, in Java, type to the conversion is very natural, not to be cast automatically, that is to say, the instance of B and C can be automatically converted into A type instance. Well, with this background knowledge, we can look at the upper bound of distribution, in Java, you can use the < extends Type>? To define an upper bound of < extends? Type> mean all belong to the subclass of Type, Type is the upper bound, we can not break heaven ah, specific second, < extends? A> means that all subclasses of A can match this wildcard. All our instances of B, C, and instances of their subclasses can match, but Base is not possible, because Base is the parent class of A, and our upper bound is A, so of course not Base. Naturally, we have the following code:

A, a = new, B (); A, B = new, C (); C, C = new, C (); List< extends; list = new; ArrayList< A> (); list.add (a); list.add (b); list.add (c); A>

We think it’s natural that it’s understandable, isn’t it? But the compiler obviously doesn’t allow us to do this, why? The type of our list uses upper bounds for wildcards, and matches all subclasses of A, and our add are subclasses of A, why not? Let us look at the < extends? A> list, we can hold any subclass of A objects, that is A, B, C examples are possible, that we are not able to < extend B> that is? < extends? A> subclass? &lt: entends C> what about? Let’s think for a while, OK, look at the following method:

Void joke (List< extends A> list) {A = new B (); A B = new, C (); C, C = new, C (); list.add (a); list.add (b); list.add (c); a (})}

Of course, the above code is not compiled, we analyze why, remember < extends? A> set the upper bound, so the parameters of the joke method is open, we can pass a < extend? A> list, can also be a < extends B> list? Also, it can be a < extends C> list?. Because the following code can be compiled:

Private static void jokeIn (List< extends? A> list) {static} / {List< extends? A> list = new; ArrayList< > List< extends) (? B> LIST1 = new; ArrayList< > (List<); extends; C> List2? = new (> ArrayList<); jokeIn (list); jokeIn (LIST1); jokeIn (List2);}

Well, the question is, when we reached the parameters in joke is List< extends? A> when the add method is acceptable, but when the parameter we pass is List< extends? B> when list.add (a) is obviously not successful, because we list will be allowed to hold a subclass of B, but A is not in this range, it is not legitimate, when the pass is List< extends? C> when? Even list.add (B) is not allowed. So this is the problem, so do not allow this code through the compiler is wise, because we cannot always guarantee the user will call the joke method strictly came in a List< extends A> parameter?.
how do you use the upper bound? In other words, how do you generate a List&lt? What about extends A&gt and list? Remember the array covariance we said at the start? The following code uses the Java language array to have an covariant capability to produce an upper bound list:

List< extends A> list = Arrays.asList (a, B);

Arrays.asList (T… Data) uses a constructor of ArrayList:

ArrayList (E[], array) {a = Objects.requireNonNull (array)}

As you can see, the covariance of the array is used so that we can pass in the Arrays.asList, so the subclass objects of A.

2, lower bounds wildcards

The upper bounds define that you can reach the highest point and beyond is illegal; the lower bound is the bottom line; you can only be more advanced than the bottom line and below the bottom line is against the law. In Java, you can use the < super Type>? To express the lower bound of the significance, specifically, < super A>? Expression of &lt and extends; A>? Is the two in the opposite direction, the former is that all A base class based on the latter is that all subclasses of A based on us look at the following methods:

Void joke (List< super A> list) {A = new B (); A B = new, C (); C, C = new, C (); list.add (a); list.add (b); list.add (c); a (})}

The parameter of the joke method is List< super, A> List&lt? At this time; super? B> and List< super? C> become List< super? A> the parent class, because in fact, List< super and List< B>?? super C> expression ability than List< super? A> more is List< super? C> contains List< super? B> and List< super, A> List&lt? Super;? B> include List< super, A>? Well, the post, let us look to the joke method call what will occur:

Static {List< super? A> list = new; ArrayList< > List< super) (? B> LIST1 = new; ArrayList< > (List<); super; C> new? List2 = ArrayList< > (jokeIn); (list); jokeIn (LIST1); / / error (jokeIn List2 //error});

Well, a problem, we can use the List< super? A> the parameters passed to the joke, because this is what we need, but we also know that List< super? A> expression in List<? Super B> and < super? C> is the lowest, so. When we will have a strong expression ability in List< super? A> after the parameters passed to the joke, the compiler error. Of course, this is only to illustrate the definition of the lower bound.

With the lower bounds, we can use the following code to work for us:

List< super A> lists = new; ArrayList< > (); lists.add (a); lists.add (b); lists.add (C);

Explain, inside the lists element type is a type that this type of A is the base class, we only define the lower bound, just above the lower bound, it can be accepted by lists, B, C of the base class is A, can be accepted by lists, so the code above is to work.

3, unbounded wildcards

The upper and lower bounds are unbounded, and one thing to note is that the upper and lower bounds cannot be used at the same time, because there is unbounded ah (joking)!!
, we use &lt in Java; > to express unbounded, for < > for the moment, the lock expression means:

I want the Java paradigm to write this code, and I don't want to use the native type here, but in this case, generic parameters can hold any type. - from Java programming idea, 15.10.3 unbounded wildcards (686 pages)

A scene with unbounded wildcards is: if you use a &lt to > the method of transfer;? A primitive type, then the compiler may infer the type parameters, so this method can turn and call another one using this exact type method. This is called type capture, look at the code below:

Static class Holder< T> T public {private data; Holder (public) {} Holder (T data) { =data;} public T getData (return) {data}; public void setData (T data) {}} = data; static < T> void; actual (Holder< T> holder System.out.println (holder.getData) {static} ()); void (Holder< func? > holder) {actual (holder);} static {Holder< > = new; holder? Holder< > ("Hujian"); func (holder);}

We can see that the actual parameter is specific to T, and the func parameter is unbounded < >?, the occurrence of a parameter type to capture things here, when calling the func type is captured, and we can use non bounded parameters passed in from the func in actual. The
object can be used to receive a plurality of unbounded wildcard types, then according to different types of delivery to the different approaches to treatment, can recall the processing method of the interrupt handler of the operating system, through the installation of some types of interruption and the corresponding handler, and then through the control program to be distributed to different signal interrupt processing in handler, in fact, idea is the same, you can look at the following code to understand the model:

Static < T> void; actual (Holder< T> holder) {T = holder.getData (data); if (data instanceof String) {actual ((String) data else if (data);} instanceof {(Integer) actual (Integer) data else if (data);} instanceof {actual Double) ((Double) data);}} static void actual (String holder) {System.out.print (string: + holder);} static void actual (Integer holder) {System.out.println (Integer: + holder);} static void actual (Double holder) {System.out.println (double: + holder);} static void func (Holder< > holder? Actual (holder) {});