Formability and configuration conversion in Java

Given the following two class definitions:

class C1<T extends C1<T>> {} class C2<U> extends C1<C2<U>> {} 

And the following type declaration:

 C1<C2<?>> a; 

Intuitively, he feels that the declared type a must be valid, but that’s not how the JDK-8u45 behaves. Instead, we get something like the following output:

 Test.java:3: error: type argument C2<?> is not within bounds of type-variable T C1<C2<?>> a; ^ where T is a type-variable: T extends C1<T> declared in class C1 1 error 

( Edit: I was dingus here, they answered this part: C2<?> Does not extend C1<C2<?>> . The problem associated with the declaration c below is still an open question.)

But C2<?> Extends C1<C2<?>> , which, it would seem, trivially satisfies the estimate. Viewing JLS gives no additional coverage, as far as I can see. It should be just as simple as satisfying the binding with a subtype relation, since C2<?> Is not a wildcard type, and therefore the capture transformation is just an identity conversion in the argument.

There are situations when it becomes a little less clear, for example, the following class definitions are accepted:

 class C3<T extends C3<?>> {} class C4<Y, Z> extends C3<C4<Z, Y>> {} class C5<X extends C3<X>> { void accept(X x); } 

All this is fine, but if we try the following declaration:

 C5<C6<?, ?>> b; 

Everything is getting weirder. C6<?, ?> Is a subtype of C3<C6<?, ?>> , so the declaration must be valid in accordance with my interpretation of the specification indicated above regarding the declaration C1<C2<?>> . The problem is that obviously not every subtype C6<?, ?> Really satisfies this estimate, so now, for example, C5.accept() resolves its parameter type C6<?, ?> And therefore can accept arguments that violate the restriction on X , i.e. Any where the parameterizations Y and Z not identical.

Where am I wrong here? How much do I not understand the subtype relationship?

( Edit: The next part of the question remains unanswered, but I translated it to a new question here , since a completely different problem is actually ... Sorry for the mess and not using the site very well haha ​​...)

In addition, I also have problems with capture conversion in similar situations. Take the following type of ad:

 C1<? extends C2<?>> c; 

Unlike a similar declaration of a at the beginning, this compiles into the JDK-8u45. If we look at the specification for capturing conversion , however, it looks like this declaration should lead to a compile-time error.

In particular, the upper bound for capturing a variable of type CAP#T is defined as glb(Bi, Ui[A1:=S1,...,An:=Sn]) , where in this case Bi allows the binding of the wildcard C2<?> And Ui[A1:=S1,...,An:=Sn] resolves to C1<CAP#T> .

From this, glb(C2<?>, C1<CAP#T>) allows the intersection type C2<?> & C1<CAP#T> , which is invalid because C2<?> And C1<CAP#T> are both class types, not interface types, but none of them is a subtype of the other.

This (obvious) violation of the rule becomes more understandable in determining the type of intersection itself .

I'm sure this is not a mistake, and I'm just making some simple mistakes somewhere ... but if no one here can shed any light on this, I will try the compiler-dev mailing list or something like that.

Thanks for any help!

+5
source share
1 answer

So far C2<x> extends C1<C2<x>> for any reference type x ,
this is not the case when C2<?> extends C1<C2<?>>

Wildcard ? not a type . This is a type argument. The syntax, however, is very misleading (by design).

Use a different syntax - if there is a 1st level wildcard, use {} instead of <> , for example

 List{?}, Map{String, ? extends Number} 

The meaning of {?} to declare a union type

 List{? extends Number} == union of List<Number>, List<Integer>, List<Long>, .... 

It is easy to see that List<Integer> is a subtype of List{? extends Number} List{? extends Number} ; and
List{? extends Number} List{? extends Number} is a subtype of List{? extends Object} List{? extends Object}

However, there is no way for Foo{?} be a subtype of a Foo<x> .


In our syntax, <> reserved for substituting a vars type with types . Therefore, we write List<String>, C2<Integer> , etc. It's easy to understand their meaning - just replace T with String in the List source code, we get a nice old simple class.

  interface List<String> String get(int) 

This cannot be done for wildcards - it does not make sense

  interface List<?> ? get(int) 

So new ArrayList{?}() , Or class MyList implements List{?} Is not allowed

So how can we use List{?} ? What methods can we name?

When the type of the expression is List{?} , We know that it is an object, and the object must belong to a subclass of List<x> for an unknown type x . This is a wildcard

 obj is a List{?} => obj is a List<x>, where xa subtype of Object. 

Even if the exact type of x not known at compile time, we can still make a replacement

  interface List<x> x get(int) 

so that we can understand the call to obj.get(0) ; it returns x , and x is a subtype of Object ; so we can assign the return value of Object .

+3
source

All Articles