Lower bounded wildcard not checked against upper bounded type parameter

南楼画角 提交于 2019-12-05 16:10:39

问题


I wonder why does this piece of code compile successfully?

Source code:

abstract class A<K extends Number>
{
    public abstract <M> A<? super M> useMe(A<? super M> k);
}

Compiled successfully

How does it work and why does this compile? M is any type, so why it can be used?. Should it be: <M extends Number>? This will not compile:

abstract class A<K extends Number>
{
    public abstract <M> A<? super M> useMe(A<M> k);
}

Error message:

type argument M is not within bounds of type variable K where M, K are type variables: M extends Object declared in method useMe(A) K extends Number declared in class A

What is the difference?


回答1:


This compiler behavior was discussed on this Eclipse bug. Originally, the Eclipse compiler did error for the expression in your example, while javac did not. Although I haven't yet searched the JLS directly, the consensus seems to be that there is nothing in the spec requiring lower bounded wildcards to be checked against type parameter bounds. In this situation it's ultimately left to the caller to assign a type that satisfies the constraints (as surmised by Stephan Herrmann on that post).




回答2:


This is a surprisingly meaningless piece of code.

All it is saying is that the class A takes a generic type K that is a Number and there is a method useMe that returns an A<T> with some pointless extra restriction on T (other than being a Number obviously).

Here's an implementation to show how little is being said by the sugar:

abstract class A<K extends Number> {
    public abstract <M> A<? super M> useMe(A<? super M> k);
}

class B extends A<Number> {

    @Override
    public <M> A<? super M> useMe(A<? super M> k) {
        // Not much more you can do here but this.
        return k;
    }

}

The ? super M stuff is just meaningless gobbledegook - all the compiler can derive from it is that both the parameter passed to it and the result returned must be a superclass of a specific unnamed class.

Generics are there to make detection of coding mistakes easy at compile time. Using mumbo-jumbo such as this is just misleading obfuscation.




回答3:


Adding <M extends Number> to the first example doesn't add anything the compiler cares about. Remember you are saying "a type which is a supertype of M" if we are saying "M is a subtype of Number" and "the type is a supertype of M", we aren't actually saying if the type is a subtype of Number.

For a better example, have M be Integer and the variable be of type A<Object>. While obviously that won't work, it satisfies all the requirements of the function correctly.

Since there exists no way to fix the function definition, it just lets it pass and assumes the call site will catch the problem.




回答4:


There are two parts to your question:

Part 1: What is the <M>?

The presence of a generic parameter on a method makes it a "typed method", which means the method has a generic type that is determined by the caller, usually by inference. It may be bounded. If the class has a type too and the method is an instance method, the two types are unrelated.

Part 2:

The generic types must match exactly. The reason boils down to the fact that if B is a subtype of A, SomeClass<T extends B> is not a subtype of SomeClass<T extends A>, more particularly, SomeClass<A> is not a subtype of SomeClass<? super A>.



来源:https://stackoverflow.com/questions/20752781/lower-bounded-wildcard-not-checked-against-upper-bounded-type-parameter

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!