![]() |
|
|
|
#1 |
|
If I have the following:
HashMap<MyKey,MyValue> map = new HashMap<MyKey,MyValue>(); MyKey myKey = new MyKey(); Then I can put in a value by: map.put(myKey, new MyValue() ); The compiler enforces the use of these two types. However to do a get I can do the following and the compiler does not complain: map.get(myKey); // this is right map.get(myKey.toString()); // this is wrong yet legal map.get(new Long(20)); // this is wrong yet legal All of these are legal according to the compiler. Why is it that the compiler does not enforce type checking on the get()? Or rather, why does the spec not say get(K key) instead of get(Object o) http://java.sun.com/javase/6/docs/ap...va.lang.Object) -- Wojtek Wojtek |
|
|
|
|
#2 |
|
Posts: n/a
|
Wojtek <> writes:
>All of these are legal according to the compiler. Why is it that the >compiler does not enforce type checking on the get()? Setting with a wrong type can result in a Map that breaks its contract. Therefore, it is forbidden. Getting with a wrong type cannot do such harm, so, it is not forbidden. After all, you can meaningfully and correctly detect at run time that for a wrong key, there is no value in the map. Stefan Ram |
|
|
|
#3 |
|
Posts: n/a
|
On Oct 28, 4:11*pm, r...@zedat.fu-berlin.de (Stefan Ram) wrote:
> Wojtek <nowh...@a.com> writes: > >All of these are legal according to the compiler. Why is it that the > >compiler does not enforce type checking on the get()? > > * Setting with a wrong type can result in a Map that breaks > * its contract. Therefore, it is forbidden. Getting with a > * wrong type cannot do such harm, so, it is not forbidden. > * After all, you can meaningfully and correctly detect at run > * time that for a wrong key, there is no value in the map. I don't understand. If the type is not the same as the type used in the map there is no chance of success. Clearly this is an error. I'm of the mind of the OP. Ken |
|
|
|
#4 |
|
Posts: n/a
|
Ken <> writes:
>I don't understand. If the type is not the same as the type used in >the map there is no chance of success. Look at the following example: public class Main { public static void main( final java.lang.String[] args ) { final java.util.Map<java.lang.String,java.lang.String> value0 = new java.util.HashMap<java.lang.String,java.lang.Strin g>(); final java.util.Map<java.lang.Object,java.lang.Integer> value1 = new java.util.HashMap<java.lang.Object,java.lang.Integ er>(); final java.util.Map <java.util.Map<java.lang.String,java.lang.String>, java.lang.String> map = new java.util.HashMap <java.util.Map<java.lang.String,java.lang.String>, java.lang.String>(); map.put( value0, "alpha" ); java.lang.System.out.println( map.get( value1 )); }} alpha »value1« has not the type used in the map, yet the »get« succeeds. Stefan Ram |
|
|
|
#5 |
|
Posts: n/a
|
Stefan Ram wrote :
> Wojtek <> writes: >> All of these are legal according to the compiler. Why is it that the >> compiler does not enforce type checking on the get()? > > Setting with a wrong type can result in a Map that breaks > its contract. Therefore, it is forbidden. Getting with a > wrong type cannot do such harm, so, it is not forbidden. > After all, you can meaningfully and correctly detect at run > time that for a wrong key, there is no value in the map. No it is not an error. Just will never retrieve ANY value if you use the wrong type (see below). This came about because I changed the key for a HashMap to one that is more specific (such as String to MyKey). All the "put" statements were caught. However ALL the get statements were not. I had to manually go through the code to locate each occurrence and change it. And of course I missed some and the code broke during runtime. I had assumed that generics would solve this type of issue. Caveat: Yes it is possible to get the same hashcode with two different types, however it would be highly unlikely. -- Wojtek Wojtek |
|
|
|
#6 |
|
Posts: n/a
|
(Stefan Ram) writes:
>Look at the following example: (...) >final java.util.Map<java.lang.String,java.lang.String> value0 >= new java.util.HashMap<java.lang.String,java.lang.Strin g>(); (...) >»value1« has not the type used in the map, yet the »get« succeeds. Above, both types were the same after type erasure and were types of empty containers. Here is a program with types that differ even after type erasure and non-empty containers. public class Main { public static void main( final java.lang.String[] args ) { final java.util.ArrayList< java.lang.String >list0 = new java.util.ArrayList< java.lang.String >(); list0.add( "text" ); final java.util.LinkedList< java.lang.String >list1 = new java.util.LinkedList< java.lang.String >(); list1.add( "text" ); final java.util.Map < java.util.ArrayList< java.lang.String >, java.lang.String >map = new java.util.HashMap < java.util.ArrayList< java.lang.String >, java.lang.String >(); map.put( list0, "value" ); java.lang.System.out.println( map.get( list1 )); }} value Stefan Ram |
|
|
|
#7 |
|
Posts: n/a
|
On 10/28/2009 05:59 PM, Wojtek wrote:
> Or rather, why does the spec not say get(K key) instead of get(Object o) I can think of some cases where it might be desirable to use gets with other objects; this requires, of course, that the objects be designed with this use case in mind, namely that the hash codes and equals work correctly. One example that came up in some code was where I had a parameter accessible in two different fashions, and the conversion between the two forms became a hotspot in the code. -- Beware of bugs in the above code; I have only proved it correct, not tried it. -- Donald E. Knuth Joshua Cranmer |
|
|
|
#8 |
|
Posts: n/a
|
Stefan Ram wrote :
>> Setting with a wrong type can result in a Map that breaks >> its contract. Therefore, it is forbidden. Getting with a >> wrong type cannot do such harm, so, it is not forbidden. >> After all, you can meaningfully and correctly detect at run >> time that for a wrong key, there is no value in the map. Wojtek wrote: > No it is not an error. Just will never retrieve ANY value if you use the > wrong type (see below). > > This came about because I changed the key for a HashMap to one that is > more specific (such as String to MyKey). All the "put" statements were > caught. However ALL the get statements were not. I had to manually go > through the code to locate each occurrence and change it. > > And of course I missed some and the code broke during runtime. I had > assumed that generics would solve this type of issue. Generics only handle what is declared generically. 'Map#get()' is not so declared. Assumptions based on falsehood will yield false conclusions. <http://java.sun.com/javase/6/docs/api/java/util/Map.html#get(java.lang.Object)> > Caveat: Yes it is possible to get the same hashcode with two different > types, however it would be highly unlikely. And this is relevant how? 'Map' retrieval is defined in terms of 'equals()', not 'hashCode()'. <http://java.sun.com/javase/6/docs/api/java/util/Map.html#get(java.lang.Object)> > ... formally, if this map contains a mapping from a key k to a value v > such that (key==null ? k==null : key.equals(k)), > then this method returns v; otherwise it returns null. > (There can be at most one such mapping.) FWIW, if 'Map#get()' had been redefined generically, it would have broken existing code without providing an improvement. Code that would have not gotten a value still does not get a value without introducing a new error. Maybe they erred in this, but they were trying to maintain backward compatibility. It's a shame that the compiler didn't find your refactoring mistake for you, but it was your mistake, not Java's. -- Lew Lew |
|
|
|
#9 |
|
Posts: n/a
|
In article <>, Wojtek <>
wrote: > If I have the following: > > HashMap<MyKey,MyValue> map = new HashMap<MyKey,MyValue>(); > MyKey myKey = new MyKey(); > > Then I can put in a value by: > > map.put(myKey, new MyValue() ); > > The compiler enforces the use of these two types. > > However to do a get I can do the following and the compiler does not > complain: > > map.get(myKey); // this is right > map.get(myKey.toString()); // this is wrong yet legal > map.get(new Long(20)); // this is wrong yet legal > > All of these are legal according to the compiler. Why is it that the > compiler does not enforce type checking on the get()? > > Or rather, why does the spec not say get(K key) instead of get(Object > o) > > http://java.sun.com/javase/6/docs/ap...(java.lang.Obj > ect) HashMap.java: public V get(Object key) There's no generics declared on the key for reading. Generics is extremely helpful for common source code mistakes but it is by no means a powerful tool. There have been many, many long threads about it here. -- I won't see Goolge Groups replies because I must filter them as spam Kevin McMurtrie |
|
|
|
#10 |
|
Posts: n/a
|
Kevin McMurtrie wrote:
> Generics is extremely helpful for common source code mistakes but it is > by no means a powerful tool. There have been many, many long threads > about it here. There may have been long threads about it, but generics most assuredly is a powerful tool. Perhaps you just haven't learned to use it correctly yet. -- Lew Lew |
|