用Java虽说时间不是很长,但也有将近两年, 不过这个LinkedHashSet还是第一次用,
以前只是在学Java的Collections时知道有这么个类,它可在Set的基础排重的基础上有List的保持原有顺序的作用.理解归理解,但实际中
还是一直也没遇到真正用它的场景. 在这篇博客里
,很遗憾与这个类仅仅是擦肩而过,也没能真正地往下想想.
在
上面那博客里提到LinkedHashSet有"排重"的作用,
其中的一个用处就是可以把List或Array中的元素放到一个HashSet里以把重复的元素去掉,不过当时没想到,用HashSet就够了,
但却为什么用了LinkedHashSet呢? 今天的一个问题逼着我想到这里LinkedHashSet的好处了:
保持List或Array里元素的顺序. 具体实例可以有: 若从数据库里取出一个List的数组,
当然可能通过SQL里的关键字distinct而在数据库里就排重,但可能出于什么特殊的考虑而没有调用distinct,这样在Java里想排重就自然
地想到了Set,而初次想到的当然也就是HashSet, 但写出来后测试时一看结果, 不对呀, 原来从数据库里取出数据明明是已Order好的,
怎么显示出的却乱了, 转念一想可不是嘛:
在用Set的HashSet排重时,它并不关心你原来数据的顺序.这时LinkedHashSet就可救火了.
进
而往下想, LinkedHashSet内部又是怎么来保序的呢? 看LinkedHashSet的源码时,没找到答案.
LinkedHashSet类里除了四个构造方法外,什么也没了. 这是怎么回事?再往下看四个构造方法中都调用了父类HashSet的构造方法,
调了又怎样呢? 难不成是HashSet也有LinkedHashSet的功能吧?
带着这个问题再看HashSet里被LinkedHashSet调用的构造方法吧, 代码如下:
HashSet(int initialCapacity, float loadFactor, boolean dummy) {
map = new LinkedHashMap<E,Object>(initialCapacity, loadFactor);
}
这
里有两个注意点,首先构造方法HashSet前没有任何访问修饰符, 也就是说只能在Java标准库里的java.util包下的类对能访问.
这也怎样呢? 下面会用到. 其次是构造方法里给map属性赋的值是一个LinkedHashMap实例. 看到这明白了:
LinkedHashSet的保序功能是通过其属性LinkedHashMap实现的. 那一般的HashSet实例怎么又没有这个功能呢?
我们看HashSet的源码发现,除上面提到的那个构造方法外,它还有四个, 这四个构造方法都是public的,
在构造方法中,属性map的值都是HashMap的实例,自然也就没有Linked*所具有的保序功能了,我们所new出来的HashSet都是通过这四
个public的构造方法生成的, 自然也就没有保序功能了.
看到这里, "保序"的实现虽说没有彻底搞明白,但知道了, 它是通过LinkedHashMap实现的, 这就不必再为
LinkedHashSet自身的实现所困惑了.如有时间再考虑人家
LinkedHashMap是怎么实现"保序"功能的.
不过,通过这个问题的研究, 另一个设计上的启示渐渐浮出水面, LinkedHashSet在设计上又有什么启示呢?在下一篇关于LinkedHashSet的思考里将做详细的说明.