public class test {
public static void main(String[] args) throws IOException {
HashMap<Integer, String> map= new HashMap<>();
map.put(1,"one");
String aa = map.get(1);
byte b =1;
String bb = map.get(b);
}
}
如上代码,为何 bb 变量是 null 呢,感觉不是 byte 自动转型为 int,再自动装箱为 Integer 吗
1
IMCA1024 Mar 30, 2020
.....Integer 做 key 啊。
为什么推荐用 String 做 key 呢? 原理我不太会说,但我觉得问题在 你这个 byte b=1 的 hash 值 并不能拿到 key 为 Integer=1 的。。 希望楼下的能给我说明一下 哈哈哈 |
2
mm163 Mar 30, 2020
HashMap<Integer, String> map= new HashMap<Integer, String>();
|
3
EPr2hh6LADQWqRVH Mar 30, 2020 via Android 要射自己脚的话直接 c++就完了嘛
|
4
earther01 Mar 30, 2020
看了下 get 前强转一下就行了,不转的话应该是认为传进去的是 object 的地址,会先寻址找到地址对应的 object
|
5
airfling Mar 30, 2020
我刚刚测试了下你没加强转的话是取 byte 的 hash 值取值的,加了强转的话就是一样的值了
下面是 map 中的 get ~~~ public V get(Object key) { Node<K,V> e; return (e = getNode(hash(key), key)) == null ? null : e.value; } ~~~ map.get((int)b) 这样获取的值就是一样的 |
6
h3nng Mar 30, 2020
补充下楼上说的,hash 值其实是一样的,都是 1,但是 == 或 equals() 为 false
|
7
amiwrong123 OP @airfling
好吧,大概懂了。我主要之前以为函数签名是泛型类型呢 public V get(K key) { |
8
p2pCoder Mar 30, 2020
只会触发装箱,没有触发转型
|
9
lux182 Mar 30, 2020
个人猜测:byte 封装为 Byte 。Byte _b = 1 与 Integer _a = 1 的 hash 、equals 应该有不同
|
10
ChenFanlin Mar 30, 2020
|
12
guyeu Mar 30, 2020
因为 HashMap.get(Object)接受任意类型的参数,当传入基本数据类型时,会触发自动装箱。
如果你声明一个这样的方法,用来替换 HashMap.get ,就会先触发类型转换,然后触发自动装箱; ```java static <T> T get(HashMap<?, T> map, int key) { return map.get(key); } ``` java 貌似不支持同一个位置既自动类型转换又自动装箱。。 |
13
elevation Mar 30, 2020
如果想彻底了解,需要学习 HashMap 源码中 put 运行机制;还有你需要写明白,自己的开发环境
|
15
amiwrong123 OP @guyeu
java 不支持同一个位置既自动类型转换又自动装箱么,回头我试下 对,自己再写个方法可以哈。话说,你那个泛型方法 应该这样吧: ```java static <K,V> V get(HashMap<K, V> map, K key) { return map.get(key); } ``` |
18
guyeu Mar 30, 2020
@amiwrong123 #15 你这样写没办法出发自动类型转换(你这个只不过是把 HashMap 自带的 get 方法换了个写法)
|
19
dreamist Mar 30, 2020
这个代码,在 Kotlin 里面是会编译报错的,所以,Kotlin 欢迎你~~ hhh
|
20
dreamist Mar 30, 2020
这个问题,究其原因,还是 HashMap 的锅,HashMap 的 get 方法参数是没有泛型约束的:
public V get(Object key) { } 所以在 get 的时候,传入的类型,是允许和 HashMap 定义时的 key 类型是不一致的,这就导致了这样的问题无法在编译期间暴露出来。 |
21
1194129822 Mar 30, 2020 via Android 楼主对 hashmap,基本类型及其包装类,自动装箱及隐私类型转换,类型提升不是很熟悉啊。首先 Java 泛型并不支持基本类型,java 默认的整型是 int,浮点数是 double,所以没有特别标注 1,2 这些字面量表示就是 int,当在泛型方法中使用时,会自动装箱为 Integer,如果强行指定(byte)1 则会包装为 Byte,hashmap 判定两个元素是否相等是 equals,而 hashcode 相同只是处在相同的 bin 中。所以当然为 null 啦,而 Integer(1)与 Byte(1)当然就不相同啦,这里还有个坑,因为 Byte,Integer 缓存了 1byte 的值,所以你 put/get(1)多少次只是 1 个包装对象,而 get(128)就会每次生成一个新对象,虽然包装类都重写了 equals,但还是会稍微影响点性能,而 java 默认的隐式类型装是针对基本类型的,换是 int 可以接受 byte,注意 Byte 不能转换为 Integer 。而类型提升也是针对基本类型的,算数位移等运算符只能是基本类型,并且默认提升到***int***,所以 byte(1)+byte(1)=int(2). 所以你只要 get(byte(1)+0)就相当于 get(1)了,推荐看一下 java 规范
|
22
xiaowangge Mar 31, 2020 1 、debug 大法好:
在 IDEA 中,在 `String bb = map.get(b);` 这一行打断点,然后 debug 运行,force step into public static Byte valueOf(byte b) { final int offset = 128; return ByteCache.cache[(int)b + offset]; } 2 、javap 大法好: 35: invokestatic #9 // Method java/lang/Byte.valueOf:(B)Ljava/lang/Byte; |
23
Aresxue Mar 31, 2020
很有趣的问题, 看了下源码 byte b 在处理时被装箱成了 Byte,有趣的是 new Byte(1)和 new Integer(1)的 hashCode 是一样的, 这很容易让人困惑, 但在 HashMap 569 行(k = first.key) == key || (key != null && key.equals(k))) 中对 key 除了 hashCode 的判断还有对类型的判断(见 Integer equals 方法 974 行)。同理你使用 map.get(new Integer(1)) 就可以取出对应的值来, 哪怕不是同一个对象也依旧可以取出你想要的值, 因为 new Integer(1) equals new Integer(1)
|
24
SoloCompany Mar 31, 2020
关键在于 Map.get 的签名是 get(Object key) 而并不是 get(K key)
虽然 put 的签名是 put(K key, V value) 然而 get 和 put 并不对等 |