7

Why does

class Foo<T> {
}

class Bar<T> {
   List<Foo<?>> getFoos() {
      return null;
   }
}

class Baz {
   void baz(Bar bar) {
      for (Foo foo : bar.getFoos()); 
//                              ^
//error: incompatible types: Object cannot be converted to Foo
   }
}

give a compiler error while

class Foo<T> {
}

// changed Bar<T> to Bar
class Bar {
   List<Foo<?>> getFoos() {
      return null;
   }
}

class Baz {
   void baz(Bar bar) {
      for (Foo foo : bar.getFoos());
   }
}

and

class Foo<T> {
}

class Bar<T> {
   List<Foo<?>> getFoos() {
      return null;
   }
}

class Baz {
   // changed Bar to Bar<?>
   void baz(Bar<?> bar) {
      for (Foo foo : bar.getFoos());
   }
}

and

class Foo<T> {
}

class Bar<T> {
   List<Foo<?>> getFoos() {
      return null;
   }
}

class Baz {
   void baz(Bar bar) {
      // changed Foo to Object
      for (Object foo : bar.getFoos());
   }
}

compile fine.

Or rather why does bar.getFoos() return List<Object> and not List<Foo<?>> if the parent instance is a raw type of a generic class?

flakes
  • 21,558
  • 8
  • 41
  • 88
Vampire
  • 35,631
  • 4
  • 76
  • 102
  • This isn't an answer but I suspect figuring out which method signatures depend on the (absent) type parameters of the raw class would've been too complicated and error-prone. And since raw types were intended only as a fallback to deal with generics-unaware code, it might have been seen as no great loss. – biziclop Apr 19 '16 at 12:30
  • All examples trigger warnings related to generics, can you clarify what you mean? – Timmos Apr 19 '16 at 12:35
  • @Timmos I talk about the hard compiler error that the first block produces, not about any warnings. – Vampire Apr 19 '16 at 12:38
  • Are all of these top-level classes? Or inner classes? Because non-static inner classes take over the generic type parameter from their parent class which could twist the problem. Please clarify. – Timmos Apr 19 '16 at 12:41
  • @Timmos Nope, plain top-level classes. Just paste the snippet in a Java file and try to compile it. – Vampire Apr 19 '16 at 12:43
  • The instance methods will follow the same erasure as its enclosing class. Notice that changing the method to `static List> getFoos()` will compile no issue – flakes Apr 19 '16 at 12:44
  • @flkes but isn't type erasure that the generics are not there at runtime? At compile-time this should work, shouldn't it? The Type parameter of the return type is not related at all to the type parameter of the class. I don't see why this should get erased at this time. – Vampire Apr 19 '16 at 12:46
  • @AndyTurner is right, though to be honest I've never liked the existing Q&As on this. When you have a raw type, you have the erasure of that type and *everything* gets erased. – Radiodef Apr 19 '16 at 12:48
  • Are you sure this is a duplicate? I can't see anywhere the correct answer, which is: `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. ` So basically all method signatures will be "raw-ified", regardless of whether their signature depended on a type parameter or not. (With the exception of inherited parameters.) – biziclop Apr 19 '16 at 12:56
  • Well, actually this question is different, as it is not about generic methods with type parameters, but about returning a generic type. But the answer is nonetheless the same. – Vampire Apr 19 '16 at 13:03
  • 1
    @OldCurmudgeon I was just about to do this :) I've edited this in to the canonical answer. (See the section *"A raw type is the erasure of that type"*.) – Radiodef Apr 19 '16 at 13:23
  • @biziclop - I think so - it is clear that the mentioned issue derives from removing the `` from `class Bar{`. This is using raw types so **all** objects are treated as `Raw`. – OldCurmudgeon Apr 19 '16 at 13:46
  • @OldCurmudgeon Okay, I might have misunderstood the question then. – biziclop Apr 19 '16 at 13:54

0 Answers0