Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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?

like image 800
soc Avatar asked May 23 '11 16:05

soc


1 Answers

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.

like image 102
finnw Avatar answered Nov 19 '22 11:11

finnw