4

The best way to explain this is with the example:

public class Cosmos<T> {
    public void says(Consumer<String> stringConsumer) {
        stringConsumer.accept("we can");
    }
}

I was expecting this would work:

new Cosmos().says(s -> System.out.println(s.length()));

But NO, this is NOT working! Java8 thinks s is an Object!

However, if I define the T with anything, it works:

new Cosmos<Void>().says(s -> System.out.println(s.length()));

How comes the methods signature is related to generic type?

igr
  • 10,199
  • 13
  • 65
  • 111
  • 3
    Possible duplicate of [Why won't this generic java code compile?](http://stackoverflow.com/questions/662191/why-wont-this-generic-java-code-compile) – MC Emperor Mar 23 '17 at 11:57
  • 6
    It's because of raw types. If you create a raw Cosmos instance, all generic uses within its class definition are also raw usages. So actually you are callsing `says(Consumer)` instead of `says(Consumer)`. – MC Emperor Mar 23 '17 at 12:00
  • 2
    Turn on all compiler warnings and *pay attention to them.* – VGR Mar 23 '17 at 12:10

1 Answers1

8

The whole concept of raw types was introduced for compatibility with pre-Generics code and consequently, using a raw type will effectively turn Generics off for all uses of this type, whether the generic signatures are related to the type’s declared type parameters or not.

This can be illustrated by the followed code example, which produces a compilation error before Java 5 and continues to produce a compilation error:

ArrayList list = new ArrayList();
String[] str = list.toArray(new String[0]);

in contrast to the generic code

ArrayList<Number> list = new ArrayList<Number>();
String[] str = list.toArray(new String[0]);

which can be compiled without errors, showing that the type parameters of toArray and the List are unrelated (a limitation of the generic type system).

Likewise, when you use new Cosmos(), the result is a raw type and invoking says on it will not use the generic type signature. But you don’t need to specify an actual type:

new Cosmos<>().says(s -> System.out.println(s.length()));

will compile without errors.

Holger
  • 285,553
  • 42
  • 434
  • 765
  • what about `public void says2(S s)`. Shouldn't the generics be erased in this case also and S become an Object? This does not compile: `new Cosmos().says2(new Object());` – Eugene Mar 24 '17 at 08:40
  • 1
    @Eugene: the erasure is the first type of the upper bound, i.e. for ``, `S` becomes `CharSequence`, like it would for ``, whereas for ``, the erasure would be `Serializable`. And for ``, the erasure would be `Object`, … – Holger Mar 24 '17 at 10:09
  • 1
    … which is interesting for methods like [this](https://docs.oracle.com/javase/8/docs/api/javax/imageio/metadata/IIOMetadataFormatImpl.html#addObjectValue-java.lang.String-java.lang.Class-T-java.lang.Comparable-java.lang.Comparable-boolean-boolean-), whose erasure has to be compatible with its [pregenerics signature](https://web.archive.org/web/20121209203056/http://docs.oracle.com/javase/1.4.2/docs/api/javax/imageio/metadata/IIOMetadataFormatImpl.html#addObjectValue(java.lang.String,%20java.lang.Class,%20java.lang.Object,%20java.lang.Comparable,%20java.lang.Comparable,%20boolean,%20boolean)). – Holger Mar 24 '17 at 10:09
  • 1
    that is... I don't even know how to put it (I am getting slowly out of positive adjectives reading your answers). Thank you for the valuable input. – Eugene Mar 24 '17 at 10:34