简体   繁体   中英

Map with integer as key returns null when long value is passed to the get method

import java.util.HashMap;
import java.util.Map;

public class StackOverFlowQuestion {

private static final int ERROR_CODE100 = -100;
private static final int ERROR_CODE101 = -101;
private static final int ERROR_CODE102 = -102;
private static final int ERROR_CODE103 = -103;
private static final int ERROR_CODE104 = -104;

public enum ErrorDetails {

    ERROR_CODE_100(ERROR_CODE100, "Error code 100 Desc", false),

    ERROR_CODE_101(ERROR_CODE101, "Error code 101 Desc", false),

    ERROR_CODE_102(ERROR_CODE102, "Error code 102 Desc", true),

    ERROR_CODE_103(ERROR_CODE103, "Error code 103 Desc", false),

    ERROR_CODE_104(ERROR_CODE104, "Error code 104 Desc", true);

    private int errorCode;
    private String errorMsg;
    private boolean canRetry;

    private ErrorDetails(int errorCode, String errorMsg, boolean canRetry) {
        this.errorCode = errorCode;
        this.errorMsg = errorMsg;
        this.canRetry = canRetry;
    }

    public String getErrorMsg() {
        return this.errorMsg;
    }

    public boolean canRetry() {
        return this.canRetry;
    }

    public String toString() {
        return "Error code : " + errorCode + ", errorMsg : " + errorMsg
                + ", canRetry : " + canRetry;
    }
}

private Map<Integer, ErrorDetails> errorMap;

public StackOverFlowQuestion() {
    System.out.println("StackOverFlowQuestion.StackOverFlowQuestion()");

    errorMap = new HashMap<Integer, StackOverFlowQuestion.ErrorDetails>();

    errorMap.put(ERROR_CODE100, ErrorDetails.ERROR_CODE_100);
    errorMap.put(ERROR_CODE101, ErrorDetails.ERROR_CODE_101);
    errorMap.put(ERROR_CODE102, ErrorDetails.ERROR_CODE_102);
    errorMap.put(ERROR_CODE103, ErrorDetails.ERROR_CODE_103);
    errorMap.put(ERROR_CODE104, ErrorDetails.ERROR_CODE_104);

    System.out.println("errorMap : " + errorMap);
}

/**
 * @param args
 */
public static void main(String[] args) {
    long param = -100;
    StackOverFlowQuestion question = new StackOverFlowQuestion();
    System.out.println("question.errorMap : " + question.errorMap);

    System.out.println("question.errorMap.containskey(param) : "
            + question.errorMap.containsKey(param));
    ErrorDetails errorDetails = question.errorMap.get(param);
    System.out.println("errorDetails : " + errorDetails);

    System.out.println("question.errorMap.containskey((int)param) : "
            + question.errorMap.containsKey((int) param));
    ErrorDetails errorDetailsWithInt = question.errorMap.get((int) param);
    System.out.println("errorDetailsWithInt : " + errorDetailsWithInt);

            int paramInt = -100;
    System.out.println("param == paramInt : " + (param == paramInt));
}

}

================================================================================= Output:

StackOverFlowQuestion.StackOverFlowQuestion()

errorMap : {-100=Error code : -100, errorMsg : Error code 100 Desc, canRetry : false, -102=Error code : -102, errorMsg : Error code 102 Desc, canRetry : true, -101=Error code : -101, errorMsg : Error code 101 Desc, canRetry : false, -104=Error code : -104, errorMsg : Error code 104 Desc, canRetry : true, -103=Error code : -103, errorMsg : Error code 103 Desc, canRetry : false}

question.errorMap : {-100=Error code : -100, errorMsg : Error code 100 Desc, canRetry : false, -102=Error code : -102, errorMsg : Error code 102 Desc, canRetry : true, -101=Error code : -101, errorMsg : Error code 101 Desc, canRetry : false, -104=Error code : -104, errorMsg : Error code 104 Desc, canRetry : true, -103=Error code : -103, errorMsg : Error code 103 Desc, canRetry : false}

question.errorMap.containskey(param) : false
errorDetails : null

question.errorMap.containskey((int)param) : true
errorDetailsWithInt : Error code : -100, errorMsg : Error code 100 Desc, canRetry : false

param == paramInt : true

=================================================================================

Here are few question which I need clarification

  1. The code is compiling even if I pass a long as the parameter to the get method of the HashMap which is declared to have only Integer as the keys. I was expecting a compilation error here, because I somehow feel this violates the strict typing.
  2. When I pass the long variable containing the error code as the parameter to the get method of the HashMap() the map returns null.
  3. When I downcast the same long parameter to an int and pass it to the get method of the hash map, the map returns the proper Enum.

I suspect the below line in the HashMap.get() method if (e.hash == hash && ((k = e.key) == key || key.equals(k)))

I am not sure whether int == long will fail or their corresponding wrappers will fail., i even added a check in the main method to verify the equality of the int and long variables.

I would like to understand the behavior here.

The code is compiling even if I pass a long as the parameter to the get method of the HashMap which is declared to have only Integer as the keys. I was expecting a compilation error here, because I somehow feel this violates the strict typing.

Did you look at the signature of Map.get ?

V get(Object key)

Any object can be used as the key. There are other Stack Overflow questions about that design decision; I'll find one later.

When I pass the long variable containing the error code as the parameter to the get method of the HashMap() the map returns null.

Yes, it would - because it will be boxed to a Long , and a Long isn't equal to an Integer . So the entry isn't found in the map.

When I downcast the same long parameter to an int and pass it to the get method of the hash map, the map returns the proper Enum.

Yes, it would - because then it will be boxed to an Integer , which will be equal to the appropriate key.

Basically you're being fooled by the fact that you can compare int and long values - that's just the compiler automatically promoting int to long for you; if you think of Integer and Long as entirely separate types, with no automatic conversion between them, the behaviour of your map makes perfect sense.

1.) The code is compiling even if I pass a long as the parameter to the get method of the HashMap which is declared to have only Integer as the keys. I was expecting a compilation error here, because I somehow feel this violates the strict typing.

No compilation error here: the only methods of Map with parameters bounded by the generic types are the put methods. get and containsKey accept an Object .

2.) When I pass the long variable containing the error code as the parameter to the get method of the HashMap() the map returns null.

When you invoke get(param) it gets translated into get(new Long(param)) . So the argument never equals the Integer keys

3.) When I downcast the same long parameter to an int and pass it to the get method of the hash map, the map returns the proper Enum.

When you invoke get((int)param) it gets translated into get(new Integer((int)param)) . So the argument type is now correct, and the result is the one you expected.

你需要将long转换为int。

Integer == Long will always fail to be equal ([Long].equal([Integer]) == false) nor might Long.hashCode() == Integer.hashCode() return the same result. Integer == Long总是不能相等([Long] .equal([Integer])== false)也不会Long.hashCode()== Integer.hashCode()返回相同的结果。

Because of Autoboxing your long will be converted into a Long, which will then be compared to any other Object with the same hashCode within the Map. Since the specific implementation of HashCode must not be equal for Long & Integer, that might already fail. If the hashCodes are the same though there is the equals check to be done, which will fail because like every equals method out there checks for "is instance of [Type]" or returns false. Which will fail in every case of comparing a Long to an Integer.

in your case is cast you long to an int or do Integer.valueOf((int)param) which will do exactly the same (autoboxing). 在你的情况下就是将你长时间转换为int或者做Integer.valueOf((int)param),这将完全相同(autoboxing)。

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM