3

Please notice the code below doesn't compile, failing on the method result assignment: String s = a.method("abc");.

The compilation error: incompatible types: java.lang.Object cannot be converted to java.lang.String

But, when changing A a to A<?> a or to A<Object> a, the compilation passes.

* Please notice that the type <T> in the method is different than the type <O> in the class.

Any idea what the compilation error? Also, why the generic definition in variable a solves the compilation issue?

class A<O>
{
    O something;

    <T> T method(T t)
    {
        return t;
    }

    static void testJavaStrangeGenericDefinitionBehavior()
    {
        A a = null;

        String s = a.method("abc");
    }
}
AlikElzin-kilaka
  • 34,335
  • 35
  • 194
  • 277
  • I'm not sure that this question is similar to the "raw type" question. I agree that the subject of "raw types" might be the answer to this question. Similar answers don't mean the questions are duplicate. – AlikElzin-kilaka Dec 06 '18 at 16:43
  • 1
    @Makoto Not really a duplicate. Is it? – Naman Dec 06 '18 at 16:45
  • 3
    @nullpointer Yes, it is, although quite hidden in the answer of that question: *Type erasure also maps the signature of a constructor or method to a signature that has no parameterized types or type variables.* – Florian Albrecht Dec 06 '18 at 16:46
  • 1
    @nullpointer: It is *very* much a duplicate. This is a classic raw type erasure problem, and there is a very detailed and complete answer in that dupe. – Makoto Dec 06 '18 at 16:47
  • Makato, why do you think a very relevant and great **answer** means a duplicate **question**? – AlikElzin-kilaka Dec 06 '18 at 16:58
  • @AlikElzin-kilaka: The answer in that other question answers your question succinctly. I do not wish to elaborate much further on this. – Makoto Dec 06 '18 at 17:45

2 Answers2

-1
A a = null;

should be:

A<String> a = null; // or better yet, new A<String>();

Although, you could substitute any class for String since, as you say, the T and O generics are different types.

Once you remove the generic parameter, you lose all the generics in your method call, which essentially becomes equivalent to calling:

Object method(Object t);
GriffeyDog
  • 8,186
  • 3
  • 22
  • 34
  • But if I change to `A`, it compiles as well. Please notice that the type in the method is different than the type in the class. – AlikElzin-kilaka Dec 06 '18 at 16:37
  • So you are saying that the Java compiler treats the static type `T` as `Object` only because the `a` uses a raw type? Indeed a little strange behaviour. – Florian Albrecht Dec 06 '18 at 16:37
  • 1
    @AlikElzin-kilaka As I mentioned, you can substitute any class for the `String`, such as `Object`. But you need to specify something for the generic type, otherwise you're dealing with raw types all the way through. – GriffeyDog Dec 06 '18 at 16:40
  • I think you could point that out in your answer a little more clear. – Florian Albrecht Dec 06 '18 at 16:41
  • See the linked duplicate that @Makoto posted. – GriffeyDog Dec 06 '18 at 16:43
  • GD, I think the key in your answer is "Once you remove the generic parameter, you lose all the generics in your method call", Can you explain it a bit more in the answer? – AlikElzin-kilaka Dec 06 '18 at 17:02
  • GD, after removing `` from the class definition, the method call line now compiles, so I'm not sure all generics are lost. – AlikElzin-kilaka Dec 06 '18 at 17:08
  • @AlikElzin-kilaka Well, sure, once you remove the you don't need to instantiate an `A` with a generic type parameter, and the method call can then remain generic (with its ``) in its own right. Since this question has been marked as a duplicate, I'm not going to expand my answer. – GriffeyDog Dec 06 '18 at 17:12
-2

It's because Java's type erasure meaning for backward compatibility all generic type declarations exist only in source code and after compilation they are converted to Object references and proper casts behind the scenes so the JVM in this case is confused that you meant O or T.

Masked Man
  • 2,176
  • 2
  • 22
  • 41