JDK之HashMap、HashSet分析
HashMap主要分析key、value的放入Map和取出Map操作以及他的遍历器。个人觉得在HashMap中有个很重要的内部类Entry,Map的put,get等重要方法都是依靠这个Entry的。先来分析下这个内部类Entry,Entry中有几个重要的变量key、value、next,不用说大家也会明白这几个变量的含义,当然也自然会有get和set方法了。当我们在遍历Map的时候,有一种方法就是获取这个内部类的对象entry,然后去这个entry中取值。现在就以这个为例,遍历一个Map。首先获取Map的entrySet集,然后获取迭代器:map.entrySet().iterator(),获取以后使用next方法拿到Entry,最后在Entry中拿到可以和Value,这种方式是首先拿到map的Entry对象,然后去拿key和value。不同于另外一种遍历方式:map.keySet().iterator(),他是先拿到key的集合,然后通过可以去取value。这两种方式最后都能遍历整个Map,但是实现的方式不一样,使用的内部类也不一样。遍历器都是在内部类中产生的,要想使用遍历器,必须使用内部类,其实在类中是不能直接调用Map中的内部类的,都是使用类中的方法,在方法中返回内部类的对象,从而去操纵内部类的方法,JDK源码中很多类都是这样操作的,这样很好影藏了内部类,但是这种做法的好处,我暂时还没有深刻体会,只觉得这样做使用了java的代理模式,也实现了java的多重继承(PS:希望有高手赐教这样使用内部类的好处和意义)。现在很细MAP中的重要方法:put。put就是将key和value放入到MAP当中,他先会拿到这个map的遍历这个map,拿到Entry,遍历map,如果有value等于当前的value,则将替换这个entry中的value,返回当前的entry,这样做是的map中key值对应的value永远只有一个,且是最新的,如果没有,则将当前这个key和value放入到entry中。在put的时候,map提供了putForNullKey方法,即,允许有key是null的,如果key是null的,则将key设置为null,跟普通的put一样,只是在比较是否存在为null的key时,不需要比较他的hash值,直接比较即可。当然,putForNullKey是私有的,只能通过put调用。map还提供了containsValue和
containsKey方法,其实现逻辑基本相同,都是变量Map,拿到Entry,然后比较key或者value。API中说Map中有两个影响其性能的参数:初始容量 和加载因子,这个不太了解,需要进一步分析。
HashSet其实底层的实现都是依赖于HashMap的,或者说他的方法实现是调用HashMap方法的。如HashSet的构造方法,就是new了一个HashMap,当向Set中add元素时,就是想Map中put值,只不过value设置为PRESENT,其中PRESENT是一个全局的object类型的对象,可以说Set其实就是一个Map,只是这个Map的value都是一样,是一个根类对象,只是key不同而已。由此可以想到为什么set中没有重复值,原因是因为Map中key是唯一的,若有重复的key,则替换的是value,此处value都一样,key肯定就唯一。当向set中添加相同元素时,都不需要异常处理,因为map的put实现方法决定了不会有异常的出现。set的其他方法不用过多分析,基本都是调用map中的方法。对于set的迭代器,他采用遍历map的方式为上面讲解的第二种map.keySet().iterator(),这样拿到map的迭代器,从而迭代set。要想很好的理解set,其实只需要理解map即可。
之所以HashMap和HashSet放在一起分析,原因很明了,其实这篇文章就是在分析HashMap。(PS:此处分析的主要是Map工作中常用的方法,可能还有很多有趣且有用的方法未分析,当用到时,需要好好的看下源码,理解这样做的理由)。