1

I have this String to String map, and I am trying to pass char as a key

Map<String, String> phone = new HashMap<String, String>() {{
    put("2", "abc");
    put("3", "def");
    put("4", "ghi");
    put("5", "jkl");
    put("6", "mno");
    put("7", "pqrs");
    put("8", "tuv");
    put("9", "wxyz");
  }};

String letterList = phone.get('2');  //null
String letterList = phone.get(String.valueOf('2'));  //it works

Why does the first case not work? In my understanding, char can be implicitly converted to String "2", and HashMap use equals() to compare keys, so that it should retrieve the key in map?

weijia_yu
  • 965
  • 4
  • 14
  • 31
  • 5
    What makes you think characters are implicitly converted to strings? – Louis Wasserman Jul 13 '19 at 23:30
  • A better question might be "Why does `HashMap.get` not throw an exception when you pass it the wrong type?" (after all, `Map.get` declared it throws ClassCastException) – Tibrogargan Jul 13 '19 at 23:58
  • 1
    Side note: Don’t use “double brace initialization” to initialize a Map. It creates a memory leak. See https://stackoverflow.com/questions/1958636/what-is-double-brace-initialization-in-java and https://blog.jooq.org/2014/12/08/dont-be-clever-the-double-curly-braces-anti-pattern/. – VGR Jul 14 '19 at 00:29

2 Answers2

5

Why does the first case not work? In my understanding, char can be implicitly converted to String "2"

Your understanding is incorrect. A char will not be implicitly converted to String. If you look at the documentation, you will see this method get(Object key). I don't know why this isn't get(K key) instead. However, this explains why your first example compiles without any errors: the char constant is autoboxed into a Character object. Since the Character with the value '2' is not a key in your Map, get() returns null.

Code-Apprentice
  • 81,660
  • 23
  • 145
  • 268
  • I see, but it passes the compiler, so somehow it converts to some string? – weijia_yu Jul 13 '19 at 23:33
  • 1
    @weijia_yu, the docs will explain everything: https://docs.oracle.com/javase/8/docs/api/java/util/Map.html#get-java.lang.Object- (i`get`accepts `Object`) –  Jul 13 '19 at 23:34
  • 2
    I see, so map didn't do type match for `get`, it accepts `Objects`, not `K` – weijia_yu Jul 13 '19 at 23:38
  • [Here](https://stackoverflow.com/questions/857420/what-are-the-reasons-why-map-getobject-key-is-not-fully-generic) is a thread about why it accepts `Object` instead of `K`. And [here's](http://smallwig.blogspot.com/2007/12/why-does-setcontains-take-object-not-e.html) an article linked in Jon Skeet's post – GBlodgett Jul 14 '19 at 00:55
2

java.util.Map uses Objects only as a key so whenever you do map.get('c') since c is a char the compiler will do autoboxing operation parsing the char c primitive into Character Object (not String as you thought)

So at the end compiler will parse the following: map.get('2') into > map.get(Character.valueOf('2'))

And since Character.valueOf('2') key does not exist in your map null is returned

Tibrogargan
  • 4,508
  • 3
  • 19
  • 38
Youans
  • 4,801
  • 1
  • 31
  • 57