黑马程序员技术博客之集合框架总结

----------- android培训java培训、java学习型技术博客、期待与您交流! ------------


Collection接口

基本操作:
添加元素:add,addAll
删除元素:remove,removeAll
求交集:retainAll

遍历用:Iterator接口

public interface Iterator{
	public boolean hasNext();
	public Object next();
	public void remove();
}

-->Set接口:没有重复项目的集合
实现了Collection接口
Set使用equals()方法来检查元素的等同性
-->HashSet——基于hash表的集合
向HashSet中存数据的时候首先判断hashCode是否相同,不相同则存储,相同则调用equals()方法,相同就不存,不同才会存储
******因此添加到HashSet的类需要覆盖hashCode()方法和equals()方法**********
对于 HashSet 而言,它是基于 HashMap 实现的,HashSet 底层采用 HashMap 来保存所有元素,因此 HashSet 的实现比较简单,查看
HashSet 的源代码,可以看到如下代码:

 public class HashSet<E> extends AbstractSet<E> 
 implements Set<E>, Cloneable, java.io.Serializable 
 { 
	 
	// 使用 HashMap 的 key 保存 HashSet 中所有元素
	 
	private transient HashMap<E,Object> map; 
	 
	// 定义一个虚拟的 Object 对象作为 HashMap 的 value 
	 
	private static final Object PRESENT = new Object(); 
	 
	... 
	 
	// 初始化 HashSet,底层会初始化一个 HashMap 
	 
	public HashSet() { 
		 
		map = new HashMap<E,Object>(); 
	 
	} 
	 
	// 以指定的 initialCapacity、loadFactor 创建 HashSet 
	 
	// 其实就是以相应的参数创建 HashMap 
	 
	public HashSet(int initialCapacity, float loadFactor) 
	 { 
		 
		map = new HashMap<E,Object>(initialCapacity, loadFactor); 
	 
	} 
	 
	public HashSet(int initialCapacity) 
	 { 
		 
		map = new HashMap<E,Object>(initialCapacity); 
	 
	} 
	 
	HashSet(int initialCapacity, float loadFactor, boolean dummy) 
	 { 
		 
		map = new LinkedHashMap<E,Object>(initialCapacity , loadFactor); 
	 
	} 
	 
	// 调用 map 的 keySet 来返回所有的 key 
	 
	public Iterator<E> iterator() 
	 { 
		 
		return map.keySet().iterator(); 
	 
	} 
	 
	// 调用 HashMap 的 size() 方法返回 Entry 的数量,就得到该 Set 里元素的个数
	 
	public int size() 
	 { 
		 
		return map.size(); 
	 
	} 
	 
	// 调用 HashMap 的 isEmpty() 判断该 HashSet 是否为空,
	 
	// 当 HashMap 为空时,对应的 HashSet 也为空
	 
	public boolean isEmpty() 
	 { 
		 
		return map.isEmpty(); 
	 
	} 
	 
	// 调用 HashMap 的 containsKey 判断是否包含指定 key 
	 
	//HashSet 的所有元素就是通过 HashMap 的 key 来保存的
	 
	public boolean contains(Object o) 
	 { 
		 
		return map.containsKey(o); 
	 
	} 
	 
	// 将指定元素放入 HashSet 中,也就是将该元素作为 key 放入 HashMap 
	 
	public boolean add(E e) 
	 { 
		 
		return map.put(e, PRESENT) == null; 
	 
	} 
	 
	// 调用 HashMap 的 remove 方法删除指定 Entry,也就删除了 HashSet 中对应的元素
	 
	public boolean remove(Object o) 
	 { 
		 
		return map.remove(o)==PRESENT; 
	 
	} 
	 
	// 调用 Map 的 clear 方法清空所有 Entry,也就清空了 HashSet 中所有元素
	 
	public void clear() 
	 { 
		 
		map.clear(); 
	 
	} 
	 
	... 
 
} 

-->LinkedHashSet——相对HashSet有顺序

LinkedHashSet集合同样是根据元素的hashCode值来决定元素的存储位置,但是它同时使用链表维护元素的次序。这样使得元素看起 来像是以插入顺序保存的,也就是说,当遍历该集合时候,LinkedHashSet将会以元素的添加顺序访问集合的元素。


-->TreeSet——基于平衡树的数据结构
TreeSet是SortedSet接口的唯一实现类,TreeSet可以确保集合元素处于排序状态。TreeSet支持两种排序方式,自然排序 和定制排序,其中自然排序为默认的排序方式。向TreeSet中加入的应该是同一个类的对象。
TreeSet判断两个对象不相等的方式是两个对象通过equals方法返回false,或者通过CompareTo方法比较没有返回0
自然排序使用要排序元素的CompareTo(Object obj)方法来比较元素之间大小关系,然后将元素按照升序排列。如使用String、Integer中的CompareTo方法进行比较。
Java提供了一个Comparable接口,该接口里定义了一个compareTo(Object obj)方法,该方法返回一个整数值,实现了该接口的对象就可以比较大小。
obj1.compareTo(obj2)方法如果返回0,则说明被比较的两个对象相等,如果返回一个正数,则表明obj1大于obj2,如果是 负数,则表明obj1小于obj2。
如果我们将两个对象的equals方法总是返回true,则这两个对象的compareTo方法返回应该返回0
定制排序
自然排序是根据集合元素的大小,以升序排列,如果要定制排序,应该使用Comparator接口,实现 int compare(T o1,T o2)方法

自然排序情况下,一个TreeSet中只允许存放同一类型的多个元素,这里要求不是自定义的类,否则会抛出ClassCastException。

当试图将对象强制转换为不是实例的子类时,抛出该异常。如试图将String类型的对象转换为Integer类型的对象。
因为TreeSet实现了Set接口,同样要求集合元素不重复,所以一样要复写hashCode()和equals()方法。

除了自然排序的情况下,存入TreeSet的类都要实现Comparator接口,复写compareTo()方法,除非仅在该集合中存入该自定义类的一个对象

-->List——有顺序,可以重复


-->ArrayList—VS—Vector:数组表
Vector:线程安全,但效率低
需要增加爱长度时Vector增长为原来一倍,ArrayList则仅增加一半。

ArrayList就是所谓的动态数组,其底层依然是Array

与Array相比:

(1)ArrayList是Array的复杂版本

ArrayList内部封装了一个Object类型的数组,从一般的意义来说,它和数组没有本质的差别,甚至于ArrayList的许多方法,如Index、IndexOf、Contains、Sort等都是在内部数组的基础上直接调用Array的对应方法。

(2)内部的Object类型的影响
对于一般的引用类型来说,这部分的影响不是很大,但是对于值类型来说,往ArrayList里面添加和修改元素,都会引起装箱和拆箱的操作,频繁的操作可能会影响一部分效率。
但是恰恰对于大多数人,多数的应用都是使用值类型的数组。
消除这个影响是没有办法的,除非你不用它,否则就要承担一部分的效率损失,不过这部分的损失不会很大。
(3)数组扩容
这是对ArrayList效率影响比较大的一个因素。
每当执行Add、AddRange、Insert、InsertRange等添加元素的方法,都会检查内部数组的容量是否不够了,如果是,它就会以当前容量的两倍来重新构建一个数组,将旧元素Copy到新数组中,然后丢弃旧数组,在这个临界点的扩容操作,应该来说是比较影响效率的。
(4)频繁的调用IndexOf、Contains等方法(Sort、BinarySearch等方法经过优化,不在此列)引起的效率损失
首先,我们要明确一点,ArrayList是动态数组,它不包括通过Key或者Value快速访问的算法,所以实际上调用IndexOf、Contains等方法是执行的简单的循环来查找元素,所以频繁的调用此类方法并不比你自己写循环并且稍作优化来的快,如果有这方面的要求,建议使用Hashtable或SortedList等键值对的集合。


-->LinkedList——双向链表
LinkedList是通过节点直接彼此连接来实现的。每一个节点都包含前一个节点的引用,后一个节点的引用和节点存储的值。当一个新节点插入时,只需要修改其中保持先后关系的节点的引用即可,当删除记录时也一样。这样就带来以下有缺点:
操作其中对象的速度快 只需要改变连接,新的节点可以在内存中的任何地方
不能随即访问 虽然存在get()方法,但是这个方法是通过遍历接点来定位的所以速度慢。
ArrayList相比于LinkedList

前者是顺序存储结构,后者是链式存储。所以前者便于查找,但插入和删除很慢;二后者查找相对较慢,但增删较快


Map接口
用于关键字/数值对

Map中通过对象来对对象进行索引,用来索引的对象叫做key,其对应的对象叫做value

这和数组其实挺相像的:数组用下表做索引,Map则用对象

数组只能存一种数据类型,Map可以存多种

-->HashMap:基于hash表的映射表

HashMap底层其实用到了hashCode,需要复写存入HashMap对象的hashCode()和equals()方法,存取的时候,先查找hashCode(),而后再根据key值遍历该hashCode下(实际上不同的hashCode可能存储在同一个顺序结构下)的table,利用key.equals()方法判断key是否相等,以便找到相应的value。

其实也就是判断Entry中的key是否与要查找的key相等,在HashMap中有一个静态内部了类Entry,有key,value,next三个重要属性

详见:HashMap的实现原理分析

-->TreeMap:基于平衡树的映射表

通过key值排序,将Entry作为节点存入Tree,拿到key值可以在Entry中得到value

-->LinkedHashMap:
相比于HashMap增加了链表,可以按照存入顺序读取

Collection VS Collections
Collection是java.util下的接口,是set和list集合结构的父接口
Collections是java.util下的类,包含各种有关集合操作的静态方法


ArrayList VS Vector
Vector是线程同步的,ArrayList不是
需要增加长度时Vector增加一倍,ArrayList增加一半


HashMap VS Hashtable
Hashtable是线程安全的
HashMap可以让空值成为一个条目的key或value
Hahtable是基于陈旧的Dictionary类,而HashMap则是Java 1.2引进的Map接口的实现


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值