波波老师好,在hashtable的实现里有两个java细节搞不明白。
来源:14-5 实现属于我们自己的哈希表
慕虎3444883
2020-03-30
1.第一个问题是 紫色框框 的部分。我发现即使我把泛型<K,V>扔掉不写,或者只在某个步骤里扔掉,运行一组测试用例(添加1000个不等的整数)都不会出现问题。我知道java的泛型机制其实只是编译时的检测而已,那这里完全不写<K,V>怎么让HashTable<K,V>的泛型和TreeMap的联系起来呢?
难道是说:虽然最后输出的toString内容一样,但是TreeMap不带<K,V>的话,输出的数字其实都是object类型引用的Integer?
如果是这样的话,那如果开辟一个某引用类型的数组,是不是本质上只是开辟了数组的length这么长的连续空间,而对于每一个数组元素其实并没有开辟空间,它们只是被限制了句柄(引用/指针)的类型而已?
2.第二个问题是 红色框框 的那部分。foreach我记得其本质就是Iterator,而Iterator应该不会遍历null吧?我记得遇到null就结束了? 但我在debug的过程里发现 这个增强for循环仍然会进去(引用类型的数组开辟后每个元素均为null),我debug的时候也看了,确实都是null,但是foreach为什么进入了呀?是不是我对Iterator的机制理解错了,我用反编译工具看了源码,但是好乱,我有点看不懂,java底层好像还用了个布尔型的值做判断时的flag。。
引申出来的问题就是:增强for循环事实上确实进去了,但是为什么我无法给每个元素赋值呢?就像图里那样,在foreach迭代一圈之后,数组还是全为null。。这看起来好奇怪啊?
我的问题似乎有点多,真的很希望bobo老师可以一一点拨,因为我debug和查资料都进行了,但还是搞不懂,实在有一些迷茫了。。
谢谢bobo老师! 愿老师在国外身体健康(疫情)。
附上我在测试时用的代码:
@Override
public String toString() {
return "HashTable_try [size=" + size + ",capa="+ M + ", data=" + Arrays.toString(data) + "]";
}
public static void main(String[] args) {
HashTable_try<Integer, Integer> test = new HashTable_try<>();
for (int i = 0; i < 1000; i++) {
test.add(i, i%20);
}
System.out.println(test);
}
1回答
-
1
对,是 Object。比如如果这么写,课程代码中的 get 就会报错,告诉你,返回值需要 V,但得到的是 Object。
“那如果开辟一个某引用类型的数组,是不是本质上只是开辟了数组的length这么长的连续空间,而对于每一个数组元素其实并没有开辟空间,它们只是被限制了句柄(引用/指针)的类型而已?”
正确!
2
foreach 循环每次取出了你的 data 中的一个元素,你的 data 中有 M 个元素,这 M 个元素初始化为 null,在 foreach 中,会分别拿到这 M 个 null。
因为 data 中的每一个元素都是空,所以其实,在你的循环中,每一个 i 都是指向 null 的一个引用,你的 i - new TreeMap<>(),本质就是让这个引用指向了一个新开的空间。但是,这个引用,和 data 没关系。这里的核心是,foreach 每次都拿到一个新的引用,指向相应的内存。
这和课程的写法完全不同:
for(int i = 0 ; i < M ; i ++) hashtable[i] = new TreeMap<>();
你的 foreach 循环,可以理解成以下代码:
for(int k = 0 ; k < M ; k ++){ TreeMap<K, V> i = hashtable[k]; i = new TreeMap<>(); }
上面的代码是不能正确给 hashtable 开空间的。请仔细理解一下二者的不同。
继续加油!:)
012020-03-31
相似问题