由两个方法写道...

 

两个方法写道


突然想起曾经和同事讨论过一些Java集合类的使用问题,有一个同事还提了个问题,“到底hashCodeequals方法是怎么回事?”

现在失业流浪在上海,没事逛逛论坛,看到许多网友也在讨论这个问题,虽然网友们很热心,但水平参差不齐,讨论内容有时让我感到疑惑和矛盾。虽然毕业不到9个月,但如今已经没有大学时代那股子发帖的热情了,现在闲下来查查资料试图寻求一个正确的答案权当解疑取乐,我也不想仅仅就解释提到的这两个方法的用法,所以我把我能想到的内容都总结起来方便以后查阅。

首先不太想重复一些数据结构的内容,为了方便下文的解释有时候还是提一下,也附上一些常用和不常用的内容方便以后查阅。

Collection不知道应该把它翻译成什么,“集合”?但是为了和Set区分开来,我把它翻译成“容器”,我们并不会经常使用到它,常用的是它的子接口,比如Set(集合), List(表), Quene(队列)。Collection提供方法比如得到元素的数量size,判断容器是不是空的isEmpty,是否包含某一个元素contains,相应的addremove某一个元素,清空整个容器内的元素clear以及经常使用到的迭代器interatorclear算是一个比较耗时的操作,其它还有用来判断包含关系containsAll,合并allAll,移除相同的元素removeAll,取交集retainAll,接口还提供数组的操作将容器中的元素组织到数组中去toArray,这些方法都被子接口继承了下来,并且具体实现也会不同。

Set可以用来装许多数据的数据结构,和数学里的集合一样,集合里不能有重复的元素,接口方面它简直就是Collection的翻版,没有什么特别的地方,最特别不过它是“集合”

List线性表,这是一个相对特别的结构,依据存储方式的不同,有顺序存储和链式存储的分别,不管怎样,它始终是线性表,所以我们可以通过索引值(index)来查找get和修改set某个元素,可以在某个位置插入add元素,可以删除remove某个位置上的元素,查找某个元素出现的位置indexOf/lastIndexOf,取线性表中某一段的内容subList(from,to),还可以把一个容器的所有元素从某个位置开始插入表中addAll(index,collection),特别实现的迭代器listIterator通过这个迭代器我们可以自由地向前向后遍历整个线性表,我们可以使用重载的listIterator(index)从某个位置开始迭代

Quene先说明一下,虽然我把它翻译成“队列”,但是你知道,这只是个接口,我们数据结构上学的队列是FIFO的,接口什么都没有实现也无所谓什么FIFO了。但把它叫做“队列”就总是要有点共同性的,队列被认为有相同的取操作,我们只能操作队列头元素,它是最具优先级迫切需要处理的元素。区别于其它Collection子接口,Quene有自己一整套的接口方法强烈建议编程时使用这些接口,你应用使用element或者peek方法来访问队列头元素,它们不会将元素取出,二者不同的是当队列没有任何元素时element抛出异常而peek返回空,正因为有这样的区别是Quene只是一个接口,它的实现类中部分队列允许队列中有空元素,而其它则不允许队列中包含空元素,同样将头元素取出的removepoll方法,前者取出头元素如果队列没有任何元素则抛出异常,后者取出头元素如果队列没有任何元素则返回空,建议是如果你使用的队列允许空元素,那么最好是使用elementremove方法,反之则使用peekpoll方法,如果你想向队列中加入元素,最好永远使用offer,如果有容量限制,当超出容量时它将返回falseadd则抛出异常

还有一个接口,就是我们经常用到的Map,它和Collection接口没有什么太大的关系,但它也是Java Collectin Framework中的一员,它表示的是Key-Value的集合,它不允许出现相同的Key。我们可以将一个键值对加入到Mapput,可以通过键取得get相应的值,也可以通过键将一个键值对从Map中移除remove,我们还可以判断某个键或某个值是否存在于MapcontainsKey/containsValue,将另一个Map中的所有键值对加入到我们的Map中只需要调用一个方法putAll,当然我们还可以清除这个Map中的所有键值对clearMap中的所有键都可以组织出来成为一个键的集合KeySet,而值也可以全部组织成一个大的集合values,很多时候我们宁愿将键值对取出来entrySet,当然不要忘记sizeisEmpty法。


碎碎念

结构上的修改:任何添加或者删除一个元素的操作,或者显示得调整底层数组的大小,设置元素的值不属于这个情况。

大凡实现了Collection接口的类其iterator方法返回的迭代器是快速失败的,当通过方法创建了迭代器之后,所有结构上的修改都会引起ConcurrentModificationException异常。于是并发修改,迭代器很快就会失败,所以不应该在生成了迭代器之后又对容器进行结构上的修改,某些迭代器可以帮助你在迭代时进行结构修改,比如ListIterator接口的addremove方法,如果你需要使用Iterator又可能要修改容器的结构,那么请先考虑类似这样的接口,或者定制一个自己的Iterator


然后是,

Set接口的常规规定使用equals方法来判断元素是否相等,常规不是绝对TreeSet使用compareTo来判断,当返回0时,认为这两个元素是相等的而不管equals的行为如何,而我们常用的HashSet则是同时根据equalshashCode方法判断元素是否相等,也就是说如果o1.equals(o2) && o1.hashCode()==o2.hashCode()true则元素相等。大量说明模式的材料告诉我们好的程序使用接口而不是实现类,因此我们经常使用Set来进行编程,而不去了解具体的Set实现,这些不同的Set行为上的不一样使得在编写类的时候不得不去多做一些事情,编写那些POJO或者JavaBean时我们最好将equalshashCodecompareTo进行统一实现,以避免不一致和混淆,至少是重写equalshashCode方法,宗旨是如果o1.equals(o2)true,那么o1.hashCode()==o2.hashCode()也应该为true,而o1.compareTo(o2)结果应为0

HashSet是无法保障顺序的,即便你没有对这个集合做任何的改变,每次迭代顺序也不一定相同。

如果期望一个有序的HashSet,可以使用LinkedHashSet,它可以维持加入的顺序,如果一个元素被加两次将则以后一次加入定。两个集合都允许null元素。

TreeSet是有序的,每一次add都将引起一次维持顺序的插入操作,它通过自然顺序或者指定的Comparator进行排序,addremovecontains时间开销都是log(n),禁止null元素。

上的三种Set都是不同步的。


List不像Set那样多约束,是相对方便简单的接口,提供的listIterator方法将返回ListIterator对象,但它仍旧是快速失败的,应该使用ListIteratoradd/remove方法在迭代时插入和删除,另外ListIterator还是可以双向访问的。

ArrayListVector大致上等同,区别在前者实现是不同步的,后者相反。它们都是几乎和数组一样简单的数据结构,它们都是大小可变的。

LinkedList功能强大使用方便,它不是一般的链表,它几乎包含所有链表的操作,可以用作堆栈,队列或者双向队列,它不是同步的。

里随便把Quene也提一下,Quene并不常用,如果你有需要使用到Quene,比如你的需求只渴望操作双端或者某一端的元素,那么使用Quene/Deque是不错的选择,但LinkedList涵盖所有Quene/Deque的功能,所以使用LinkedList就可以满足你的需求。JDK另外实现了一个以数组形式存储的ArrayDeque,没什么太特殊的,只是存储形式不一样而已,双端操作的效率当然是链式存储快一些。

我曾经使用过的PriorityQuene基于优先级元素按自然顺序或者根据构造队列时指定的Comparator进行排序,不允许出现null元素,不允许插入不可比较的对象(没有实现Comparable接口)。迭代器并不保证迭代时的顺序,如果要按照顺序遍历,最好使用Arrays.sort(priorityQuene.toArray())PriorityQuenoffer/poll/remove/add方法时间效率为log(n)remove(object)/contains(object)方法提供线性时间,获取方法peek/element/size提供常数级时间,因此获取的时间效率是很高的,它也不是同步的。

StackVector的子类,是专门为同步需要设计的栈。


MapSet差不多,只是Map存储键值对,常规规定是不允许有相同的Key,但像TreeMap,有点类似于TreeSet,它通过compareTo进行比较保持有序,完全无视equals的行为,TreeMap是不同步的,时间开销是稳定的log(n)HashMap则是无序的,它有点类似HashSet,同时根据equalshashCode方法来判定Key是否相等,所以用于Key的对象必须实现这两个方法,与之对应是有序的LinkedHashMap,它们都是不同步的,都允许空值和空键。

Hashtable是同步的,禁止空键空值,同HashMap一样同时根据equalshashCode方法来判定Key是否相等,所以用于Key的对象必须实现这两个方法。


后,

游戏了,懒得总结。


 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值