Why do raw types in one place cause generic callsites somewhere else to be treated as raw?
Asked Answered
F

2

12

Consider this example:

import java.util.*;

class Foo<T> {
  public int baz(List<String> stringlist) { return 1; }
  public int baz(ArrayList<Object> objectlist) { return 2; }

  public static void main(String[] args) {
    Foo<String> foo = new Foo<String>(); // (A)
    //Foo foo = new Foo();               // (B)

    System.out.println(foo.baz(new ArrayList<String>()));
  }
}

Why does it print 1 in (A), but 2 with (B)?

I know how method resolution works, so no need to explain that to me.

I want to know the deeper motivation behind this "feature". Why is there no erasure warning about it? (There is just one about Foo foo = new Foo().)

Why does method resolution use erased semantics although the generic type is given?

Feinstein answered 23/5, 2011 at 16:47 Comment(0)
S
5

It's because when the compiler is resolving overloads, it considers each method as either generic or non-generic, never a mixture of the two, so the candidates are:

  1. Foo<T>.baz(List<String>)
  2. Foo<T>.baz(ArrayList<Object>)

if foo is a Foo<String>, or

  1. Foo.baz(List)
  2. Foo.baz(ArrayList)

if foo is a Foo.

There is no such thing as Foo.baz(List<String>). Either all type parameters are considered or none are. (I am not aware of this being explicitly stated in the JLS, but it makes sense since treating a generic method as if it were the raw equivalent is a backwards-compatibility feature.)

In the first case, Foo<T>.baz(List<String>) matches but Foo<T>.baz(ArrayList<Object>) does not.

In the second case both functions match, and Foo.baz(ArrayList) is more specific, so it is chosen.

Sachiko answered 23/5, 2011 at 18:53 Comment(0)
C
0

It won't even compile case (A) if you only keep the single method baz(ArrayList<Object>) (error: method cannot be applied to given type). I guess ArrayList<String> is not a subclass of ArrayList<Object>.

It's weird that it does compile in case (B), but they must have taken some weird decisions to kept backward compatibility with non-generic collections.

Courser answered 23/5, 2011 at 18:7 Comment(1)
Sure it isn't. ArrayLists element type isn't defined as covariant.Feinstein

© 2022 - 2024 — McMap. All rights reserved.