Explicit method type parameter ignored on a raw class type; compiler bug? [duplicate]

蓝咒 提交于 2019-12-01 04:26:04

问题


I am getting a compiler error calling a generic method with explicit type parameters, as if the explicit type parameter had not been taken into account. Minimal example:

class CastExample {
    static class ThingProducer<S> {
        public <T> T getThing() { return null; }
    }

    static class ThingA {}

    public static void main(String... args) {
        ThingProducer thingProducer = new ThingProducer();
        ThingA thingA = thingProducer.<ThingA>getThing(); // compile error here
    }
}

ThingProducer is a raw type since the class has a type parameter, but in calling getThing we are not referencing the class type parameter, but instead providing the method type parameter. Per my understanding of the JLS, this should be legal, but it gives me this error:

incompatible types: Object cannot be converted to ThingA

The error disappears if I

  • remove the <S> from ThingProducer
  • or make getThing static
  • declare thingProducer ThingProducer<?> instead of the raw type ThingProducer

Is this a compiler bug? If not, what rule in the JLS defines this behavior?


回答1:


Section 4.8 of the Java Language Specification answers your question:

The type of a constructor (§8.8), instance method (§8.4, §9.4), or non-static field (§8.3) of a raw type C that is not inherited from its superclasses or superinterfaces is the raw type that corresponds to the erasure of its type in the generic declaration corresponding to C.

In your example, getThing() is an "instance method ... of a raw type C [in this case, ThingProducer] which is not inherited". According to the JLS, its type is "the raw type that corresponds to the erasure of its type in the generic declaration". In the generic declaration of getThing() its type T is unbounded, which means its erasure is java.lang.Object.

Note that the spec does not say that getThing()'s type is the type constructed by erasing the raw type of which it is a member (that is, ThingProducer) -- it is actually the erasure of getThing() itself, which means that both type parameters (T and S) are erased.

[Aside: In my original answer, I quoted another sentence of the spec: "It is a compile-time error to pass type arguments to a non-static type member of a raw type that is not inherited from its superclasses or superinterfaces." My original reading of that sentence was that the compiler is required to emit a compile-time error for your syntax above, since I concluded that you were attempting to "pass type arguments to a non-static type member of a raw type". But I've changed my mind: I believe that last sentence is referring to a non-static type member (that is, a nested type), not merely a non-static generic member.]

Of course, no discussion of section 4.8 is complete without quoting this bit from the spec:

The use of raw types is allowed only as a concession to compatibility of legacy code. The use of raw types in code written after the introduction of generics into the Java programming language is strongly discouraged. It is possible that future versions of the Java programming language will disallow the use of raw types.




回答2:


As a complement to the accepted answer, if you're just looking to fix the compile error as simply as possible, and you're not using the class's type parameter <S>, the most appropriate fix (thanks @Tunaki) is

ThingProducer<?> thingProducer = new ThingProducer();

instead of

ThingProducer thingProducer = new ThingProducer();

which keeps us in the world of generics, whilst documenting that it doesn't matter what the type parameter is.

(In this cut-down example, it would make more sense to change ThingProducer, but I suspect in the real world anyone getting this error is probably dealing with a legacy class they can't change - that was my case at least.)



来源:https://stackoverflow.com/questions/33735899/explicit-method-type-parameter-ignored-on-a-raw-class-type-compiler-bug

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