1

I have a class, GraphSearch, defined as such:

public class GraphSearch{
///code
}

In this class is the generics-parameterized method:

public static <T> int dsp(T start, Map<T, List<Pair<T, Integer>>> adjList, T goal) {
///code}

I have a main I do this setup and call the method as such:

GraphSearch g = new GraphSearch();
HashMap<String,ArrayList<Pair<String,Integer>>> k = new  HashMap<String, ArrayList<Pair<String, Integer>>>();
////various setup to fill my map with valid stuff
///Pair is a class I made in my package

Then in main is

System.out.println("dsp from A to E is" + g.dsp("a", k, "e"));

I get an error.

The method dsp(T, Map<T,List<Pair<T,Integer>>>, T) in the type GraphSearch is not applicable for the arguments (String, HashMap<String,ArrayList<Pair<String,Integer>>>, String)

Well, why not? Is an ArrayList not a List? Is a String not a Generic-acceptable type? Is a Hashmap not a Map?

What's going on?

PinkElephantsOnParade
  • 6,452
  • 12
  • 53
  • 91

2 Answers2

3

The problem here is subtle, but it's based in the fact that in Java generics, a Type<A> is not a Type<B>, even if A extends B. Here, A is ArrayList, and B is List.

You defined a HashMap<String,ArrayList<Pair<String,Integer>>>, but your method expects a Map<String,List<Pair<String,Integer>>>. Try defining k with List instead of ArrayList, and it should work:

HashMap<String,List<Pair<String,Integer>>> k =
    new HashMap<String, List<Pair<String, Integer>>>();

OR define your dsp method to work with ArrayList instead:

public static <T> int dsp(T start, Map<T, ArrayList<Pair<T, Integer>>> adjList, T goal) {

Additionally, even if it's allowed, you should access static methods such as dsp via an instance of the class. It's preferred to access it with the class name, for clarity:

// GraphSearch.dsp instead of g.dsp.
System.out.println("dsp from A to E is" + GraphSearch.dsp("a", k, "e"));
Community
  • 1
  • 1
rgettman
  • 176,041
  • 30
  • 275
  • 357
  • Wow... that is rather bizarre, I think. It seems NOT intuitive to me that I can get away with "replacing" Map with Hashmap but not List with ArrayList in my definition of such an Object. But maybe I'm looking at it in an uneducated viewpoint. – PinkElephantsOnParade Oct 26 '13 at 01:06
  • It is counter-intuitive. but think links rgettman and I provided show why it's the case. – yshavit Oct 26 '13 at 17:25
3

Because Map<T, ArrayList<...>> is not a subtype of Map<T, List<...>>. See this thread (among others) for why.

Your generic should be Map<T, ? extends List<Pair<T, Integer>>> if you want to support that use case.

Another alternative would be to change k to be of type Map<String,List<Pair<String,Integer>>> -- this is preferable even if you do use the ? extends syntax, as it lets you program to the interfaces and use polymorphism better. For instance, you won't have to change k if you later decide that the values should be LinkedLists instead of ArrayLists.

Community
  • 1
  • 1
yshavit
  • 42,327
  • 7
  • 87
  • 124