在Java的学习过程中,我们时常需要用到集合,今天我给大家简单讲解一下,资料有很多来源于网络,如有不当之处,敬请指正,谢谢。
在Java中集合如果以实现的接口区分,大致可以分成两类,一.Collection接口,二.Map接口。注意集合中只能保存引用类型,不可以保存基本数据类型。下面是一张类框图,大家可以看一下:
①Collection接口
Collection是集合框架的顶级接口,它的子接口分别是List和Set,它依赖Iterator,所以它的子接口的实现类都可以使用iterator()返回该集合的迭代器对象。迭代器可以遍历集合对象,它描述了遍历集合的常见方法,该对象是以内部类的形式存在于每个集合类的内部。
1.List接口
特点:有序,对象可以重复
遍历方式:
1. for循环(利用下标)
2. foreach(jdk版本需大于1.5)
3. 迭代器iterator
List优化:
优化只需指定初始容量就可以了
①Vector
java.util.vector提供了向量类Vector以实现了类似动态数组的功能,在Java语言中没有指针的概念,但如果正确灵活的使用指针又确实可以大大提高程序质量。创建一个向量类的对象后,可以往其中随意插入不同类的对象,即不需要顾及类型,也不需要预先选定向量的容量,并可以方便地进行查找。对于预先不知或者不愿预定义数组大小,并且需要频繁地进行查找,插入,删除工作的情况,可以考虑使用向量类。
Vector是同步访问的(每个公开方法都加了锁旗标——synchronized),它包含了很多传统的方法,这些方法不属于集合框架。主要用在事先不知道数组大小,或者只是需要一个可以改变大小的数组的情况。
Vector类支持4中构造函数(构造方法)。
第一种——无参构造函数,默认大小为10:
/**
* Constructs an empty vector so that its internal data array
* has size {@code 10} and its standard capacity increment is
* zero.
*/
public Vector() {
this(10);
}
第二种——创建指定大小的Vector:
/**
* Constructs an empty vector with the specified initial capacity and
* with its capacity increment equal to zero.
*
* @param initialCapacity the initial capacity of the vector
* @throws IllegalArgumentException if the specified initial capacity
* is negative
*/
public Vector(int initialCapacity) {
this(initialCapacity, 0);
}
第三种——创建指定大小的Vector,并且增量用capacityIncrement指定(增量表示Vector每次增加的元素数目):
/**
* Constructs an empty vector with the specified initial capacity and
* capacity increment.
*
* @param initialCapacity the initial capacity of the vector
* @param capacityIncrement the amount by which the capacity is
* increased when the vector overflows
* @throws IllegalArgumentException if the specified initial capacity
* is negative
*/
public Vector(int initialCapacity, int capacityIncrement) {
super();
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
this.elementData = new Object[initialCapacity];
this.capacityIncrement = capacityIncrement;
}
第四种——创建一个包含指定collection的元素的列表,这些元素是按照该collection的迭代器返回它们的排列顺序的:
/**
* Constructs a vector containing the elements of the specified
* collection, in the order they are returned by the collection's
* iterator.
*
* @param c the collection whose elements are to be placed into this
* vector
* @throws NullPointerException if the specified collection is null
* @since 1.2
*/
public Vector(Collection<? extends E> c) {
elementData = c.toArray();
elementCount = elementData.length;
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, elementCount, Object[].class);
}
最后就是Vector除了从父类继承的方法外,还定义了以下方法:
②ArrayList
ArrayList初始化长度为0,是一个Object类型的空数组,第一次调用add()方法后,长度变为10,当数组首次扩容的10个空间用完后,需要扩容时会走grow()方法来扩容(每次扩容后的容量为上一次容量的1.5倍)。
因为底层是基于动态数组实现的,所以它使用索引(index)在数组中搜索和读取数据是比较快的,可以直接返回数组中index位置的元素,因此在随机访问集合元素上有较好的性能。但是要增加,删除数据会开销比较大,因为这需要移动增加的元素,或删除的元素位置之后的所有元素。ArrayList需要的内存相对LinkedList较少(ArrayList空间浪费主要体现在在List列表的尾部预留一定的容量空间),因为它的每个索引的位置存储的是实际的数据。
如果应用程序对数据有较多的随机访问,优先考虑ArrayList。(注意:ArrayList的增加,删除操作不一定慢于LinkedList,如果在List中间或者靠近末尾的地方增加,删除那么ArrayList只需要移动较少的数据,而LinkedList则需要一直查找到列表中间或尾部(后面会讲解),反而耗费时间较多,这时ArrayList就比LinkedList要快)。
ArrayList中有三个构造函数,下面进行讲解:
第一种——无参构造函数:
/**
* Constructs an empty list with an initial capacity of ten.
*/
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
第二种——可以指定集合的大小,以减少扩容的次数,提高写入效率:
/**
* Constructs an empty list with the specified initial capacity.
*
* @param initialCapacity the initial capacity of the list
* @throws IllegalArgumentException if the specified initial capacity
* is negative
*/
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
第三种——创建一个包含指定collection的元素的列表,这些元素是按照该collection的迭代器返回它们的排列顺序的:
/**
* Constructs a list containing the elements of the specified
* collection, in the order they are returned by the collection's
* iterator.
*
* @param c the collection whose elements are to be placed into this list
* @throws NullPointerException if the specified collection is null
*/
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
if ((size = elementData.length) != 0) {
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
// replace with empty array.
this.elementData = EMPTY_ELEMENTDATA;
}
}
③LinkedList
LinkedList底层为双链表,每个节点有item自身,prev和next两个节点来维护双链表的关系,其他的功能都是围绕双链表来进行的。由于LinkedList基于链表,所以它没有固定容量,且不需要扩容,但是它需要较多的内存,因为LinkedList的每个节点存储的除了自己本身的数据之外还需要额外存储前后节点的元素的引用。
LinkedList的优点是性能稳定,它的删除和增加操作都只需要改变前后相邻元素的引用地址,但是由于内存地址不是连续的,所以在顺序访问或者随机访问时效率较低。
LinkedList的构造函数:
第一种——无参构造函数:
/**
* Constructs an empty list.
*/
public LinkedList() {
}
第二种——有参构造函数调用了无参构造函数,并且调用了addAll()函数。(addAll()函数的主要作用是将指定集合的所有元素添加到当前列表的尾部,按照指定集合的顺序插入,如果在操作进行时修改指定的集合,则此操作的行为是不确定的):
/**
* Constructs a list containing the elements of the specified
* collection, in the order they are returned by the collection's
* iterator.
*
* @param c the collection whose elements are to be placed into this list
* @throws NullPointerException if the specified collection is null
*/
public LinkedList(Collection<? extends E> c) {
this();
addAll(c);
}
2.Set接口
特点:无序,对象不允许重复(使用eqauls()进行比较,从Object继承而来,默认比较内存地址)
遍历方式:
1. foreach(jdk版本需大于1.5)
2. 迭代器iterator
①HashSet
HashSet底层数据结构采用哈希表实现,元素无序且唯一(元素的唯一性是靠所存储元素类型是否重写hashCode()和equals()方法来保证的。过程:存储元素首先会使用hash()算法函数生成一个int类型hashCode散列值,然后与已经存储的元素的hashCode值比较,如果hashCode相等,此时就会调用equals()函数判断两个对象是否相等,如果相等,则判定为同一个对象,无需存储;如果调用equals()比较不相等,那么就是不同的对象,此时就会采用哈希的解决地址冲突算法,在当前hashCode值处类似一个新的链表,在同一个hashCode值的后面存储不同的对象,这样就可以保证元素的唯一性),线程不安全,效率较高,可以存储null元素。
HashSet采用哈希算法,底层用数组存储数据,实际为一个HashMap的实例。默认初始化容量是16,加载因子为0.75。HashSet取值的时候是调用值本身来取值的,所以不能重复。
HashSet的构造函数:
第一种——无参构造函数,创建一个默认初始大小为16的容器:
/**
* Constructs a new, empty set; the backing <tt>HashMap</tt> instance has
* default initial capacity (16) and load factor (0.75).
*/
public HashSet() {
map = new HashMap<>();
}
第二种——指定初始容量,默认加载因子:
/**
* Constructs a new, empty set; the backing <tt>HashMap</tt> instance has
* the specified initial capacity and default load factor (0.75).
*
* @param initialCapacity the initial capacity of the hash table
* @throws IllegalArgumentException if the initial capacity is less
* than zero
*/
public HashSet(int initialCapacity) {
map = new HashMap<>(initialCapacity);
}
第三种——指定初始容量,指定加载因子:
/**
* Constructs a new, empty set; the backing <tt>HashMap</tt> instance has
* the specified initial capacity and the specified load factor.
*
* @param initialCapacity the initial capacity of the hash map
* @param loadFactor the load factor of the hash map
* @throws IllegalArgumentException if the initial capacity is less
* than zero, or if the load factor is nonpositive
*/
public HashSet(int initialCapacity, float loadFactor) {
map = new HashMap<>(initialCapacity, loadFactor);
}
第四种——包含指定collection中的元素:
/**
* Constructs a new set containing the elements in the specified
* collection. The <tt>HashMap</tt> is created with default load factor
* (0.75) and an initial capacity sufficient to contain the elements in
* the specified collection.
*
* @param c the collection whose elements are to be placed into this set
* @throws NullPointerException if the specified collection is null
*/
public HashSet(Collection<? extends E> c) {
map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
addAll(c);
}
②TreeSet
TreeSet底层数据结构采用二叉树来实现,元素唯一且已经排好序(唯一性的保证需要重写hashCode()和equals()方法,二叉树结构保证了元素的有序性。可以分为自然排序和比较器排序,自然排序要求元素必须实现Comparable接口,并重写compareTo()方法,元素通过比较返回的int值判断排序序列;比较器排序需要在TreeSet初始化时传入一个实现了Comparator接口的比较器对象,或者采用匿名内部类的方式,需要重写compare()函数,元素同样通过比较返回的int值判断排序序列)。
TreeSet是基于TreeMap实现的,并且是非线程安全的。在set集合中,TreeSet插入数据是最慢的,因为它需要实现内部排序,可以自定义排序规则,并且TreeSet不允许null值插入。
TreeSet的构造函数:
第一种——无参构造函数,使用该构造函数,TreeSet中的元素将按照自然排序进行排列:
/**
* Constructs a new, empty tree set, sorted according to the
* natural ordering of its elements. All elements inserted into
* the set must implement the {@link Comparable} interface.
* Furthermore, all such elements must be <i>mutually
* comparable</i>: {@code e1.compareTo(e2)} must not throw a
* {@code ClassCastException} for any elements {@code e1} and
* {@code e2} in the set. If the user attempts to add an element
* to the set that violates this constraint (for example, the user
* attempts to add a string element to a set whose elements are
* integers), the {@code add} call will throw a
* {@code ClassCastException}.
*/
public TreeSet() {
this(new TreeMap<E,Object>());
}
第二种——指定TreeSet的比较器:
/**
* Constructs a new, empty tree set, sorted according to the specified
* comparator. All elements inserted into the set must be <i>mutually
* comparable</i> by the specified comparator: {@code comparator.compare(e1,
* e2)} must not throw a {@code ClassCastException} for any elements
* {@code e1} and {@code e2} in the set. If the user attempts to add
* an element to the set that violates this constraint, the
* {@code add} call will throw a {@code ClassCastException}.
*
* @param comparator the comparator that will be used to order this set.
* If {@code null}, the {@linkplain Comparable natural
* ordering} of the elements will be used.
*/
public TreeSet(Comparator<? super E> comparator) {
this(new TreeMap<>(comparator));
}
第三种——包含指定set:
/**
* Constructs a new tree set containing the same elements and
* using the same ordering as the specified sorted set.
*
* @param s sorted set whose elements will comprise the new set
* @throws NullPointerException if the specified sorted set is null
*/
public TreeSet(SortedSet<E> s) {
this(s.comparator());
addAll(s);
}
第四种——包含指定collection
/**
* Constructs a new tree set containing the elements in the specified
* collection, sorted according to the <i>natural ordering</i> of its
* elements. All elements inserted into the set must implement the
* {@link Comparable} interface. Furthermore, all such elements must be
* <i>mutually comparable</i>: {@code e1.compareTo(e2)} must not throw a
* {@code ClassCastException} for any elements {@code e1} and
* {@code e2} in the set.
*
* @param c collection whose elements will comprise the new set
* @throws ClassCastException if the elements in {@code c} are
* not {@link Comparable}, or are not mutually comparable
* @throws NullPointerException if the specified collection is null
*/
public TreeSet(Collection<? extends E> c) {
this();
addAll(c);
}
③LinkedHashSet
LinkedHashSet直接继承于HashSet,是一个哈希表和双向链表的结合,能够维护元素插入集合的顺序,并且在遍历时,按照此顺序进行遍历。LinkedHashSet使用LinkedHashMap对象来存储它的元素,插入到LinkedHashSet中的元素实际上是被当做LinkedHashMap的键保存起来的,它允许null值的插入。
LinkedHashSet的构造函数都是调用它的父类HashSet的同一个构造函数,这个构造函数是一个包内私有的,它只能被LinkedHashSet使用。这个构造函数需要初始容量,加载因子和一个boolean类型的哑值(没什么用的参数,作为标记,用来区分这个构造函数和HashSet的另一个指定初始容量和指定加载因子的构造函数)。
/**
* Constructs a new, empty linked hash set with the specified initial
* capacity and load factor.
*
* @param initialCapacity the initial capacity of the linked hash set
* @param loadFactor the load factor of the linked hash set
* @throws IllegalArgumentException if the initial capacity is less
* than zero, or if the load factor is nonpositive
*/
public LinkedHashSet(int initialCapacity, float loadFactor) {
super(initialCapacity, loadFactor, true);
}
/**
* Constructs a new, empty linked hash set with the specified initial
* capacity and the default load factor (0.75).
*
* @param initialCapacity the initial capacity of the LinkedHashSet
* @throws IllegalArgumentException if the initial capacity is less
* than zero
*/
public LinkedHashSet(int initialCapacity) {
super(initialCapacity, .75f, true);
}
/**
* Constructs a new, empty linked hash set with the default initial
* capacity (16) and load factor (0.75).
*/
public LinkedHashSet() {
super(16, .75f, true);
}
/**
* Constructs a new linked hash set with the same elements as the
* specified collection. The linked hash set is created with an initial
* capacity sufficient to hold the elements in the specified collection
* and the default load factor (0.75).
*
* @param c the collection whose elements are to be placed into
* this set
* @throws NullPointerException if the specified collection is null
*/
public LinkedHashSet(Collection<? extends E> c) {
super(Math.max(2*c.size(), 11), .75f, true);
addAll(c);
}
②Map接口
Map接口没有继承Collection接口,Map是将键映射到值的对象,一个映射不能包含重复的键,每个键最多只能映射到一个值。
Map接口和Collection接口的区别:①Map是双列的,Collection是单列的;②Map集合的数据结构只针对键有效,跟值无关;Collection集合的数据结构是针对元素有效;③Map的键唯一,Collection的子接口Set的元素唯一。Map中包括了一个内部类Entry,该类封装一个键值对。
Map集合的key和value都可以是任何引用类型的数据。key不可重复,value可以重复,如果key重复,那么重复键将覆盖旧键。
遍历方式:
1. keySet()——先取出保存所有键的set集合,再遍历所有键取值
2. entrySet()——先取出保存所有Entry的Set集合,再遍历此Set即可
1.HashMap
HashMap在jdk1.8之前的实现方式是数组+链表,但是在jdk1.8对HashMap进行了底层优化,改成了数组+链表+红黑树实现,主要目的就是提高查询效率。
HashMap的key和value都允许为null,线程不安全。HashMap使用的是懒加载,只有调用put()函数插入元素时,才会初始化,初始大小为16,加载因子为0.75。
HashMap的构造函数:
第一种——无参构造函数,默认初始容量16,默认加载因子0.75:
/**
* Constructs an empty <tt>HashMap</tt> with the default initial capacity
* (16) and the default load factor (0.75).
*/
public HashMap() {
this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
}
第二种——创建一个指定初始容量和默认加载因子的空HashMap:
/**
* Constructs an empty <tt>HashMap</tt> with the specified initial
* capacity and the default load factor (0.75).
*
* @param initialCapacity the initial capacity.
* @throws IllegalArgumentException if the initial capacity is negative.
*/
public HashMap(int initialCapacity) {
this(initialCapacity, DEFAULT_LOAD_FACTOR);
}
第三种——创建一个指定初始容量和指定加载因子的空HashMap:
/**
* Constructs an empty <tt>HashMap</tt> with the specified initial
* capacity and load factor.
*
* @param initialCapacity the initial capacity
* @param loadFactor the load factor
* @throws IllegalArgumentException if the initial capacity is negative
* or the load factor is nonpositive
*/
public HashMap(int initialCapacity, float loadFactor) {
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal initial capacity: " +
initialCapacity);
if (initialCapacity > MAXIMUM_CAPACITY)
initialCapacity = MAXIMUM_CAPACITY;
if (loadFactor <= 0 || Float.isNaN(loadFactor))
throw new IllegalArgumentException("Illegal load factor: " +
loadFactor);
this.loadFactor = loadFactor;
this.threshold = tableSizeFor(initialCapacity);
}
第四种——传入一个Map集合,将Map集合中元素Map.Entry全部添加进HashMap实例中:
/**
* Constructs a new <tt>HashMap</tt> with the same mappings as the
* specified <tt>Map</tt>. The <tt>HashMap</tt> is created with
* default load factor (0.75) and an initial capacity sufficient to
* hold the mappings in the specified <tt>Map</tt>.
*
* @param m the map whose mappings are to be placed in this map
* @throws NullPointerException if the specified map is null
*/
public HashMap(Map<? extends K, ? extends V> m) {
this.loadFactor = DEFAULT_LOAD_FACTOR;
putMapEntries(m, false);
}
2.Hashtable
Hashtable和HashMap一样都是基于哈希表实现的,每个元素同样是一个键值对(key-value),但其内部只是通过单链表解决哈希冲突问题,而没有红黑树结构。Hashtable采用“拉链法”实现哈希表,是一个散列表,它的公开函数大部分都是同步的(加了锁旗标——synchronized),所以它是线程安全的。
Hashtable的键(key)和值(value)都不允许为null,并且Hashtable中的映射不是有序的,它的实现结构是数组+单向链表(提示一下:Hashtable并没有遵循驼峰命名法,现在基本上已经被弃用了)。
Hashtable的构造函数:
/**
* Constructs a new, empty hashtable with the specified initial
* capacity and the specified load factor.
*
* @param initialCapacity the initial capacity of the hashtable.
* @param loadFactor the load factor of the hashtable.
* @exception IllegalArgumentException if the initial capacity is less
* than zero, or if the load factor is nonpositive.
*/
public Hashtable(int initialCapacity, float loadFactor) {
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
if (loadFactor <= 0 || Float.isNaN(loadFactor))
throw new IllegalArgumentException("Illegal Load: "+loadFactor);
if (initialCapacity==0)
initialCapacity = 1;
this.loadFactor = loadFactor;
table = new Entry<?,?>[initialCapacity];
threshold = (int)Math.min(initialCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
}
/**
* Constructs a new, empty hashtable with the specified initial capacity
* and default load factor (0.75).
*
* @param initialCapacity the initial capacity of the hashtable.
* @exception IllegalArgumentException if the initial capacity is less
* than zero.
*/
public Hashtable(int initialCapacity) {
this(initialCapacity, 0.75f);
}
/**
* Constructs a new, empty hashtable with a default initial capacity (11)
* and load factor (0.75).
*/
public Hashtable() {
this(11, 0.75f);
}
/**
* Constructs a new hashtable with the same mappings as the given
* Map. The hashtable is created with an initial capacity sufficient to
* hold the mappings in the given Map and a default load factor (0.75).
*
* @param t the map whose mappings are to be placed in this map.
* @throws NullPointerException if the specified map is null.
* @since 1.2
*/
public Hashtable(Map<? extends K, ? extends V> t) {
this(Math.max(2*t.size(), 11), 0.75f);
putAll(t);
}
3.LinkedHashMap
LinkedHashMap是HashMap和双向链表的结合,它是一个将所有Node节点链入一个双向链表的HashMap。LinkedHashMap通过维护一个额外的双向链表保证了迭代顺序,特别的,该迭代顺序可以是插入顺序,也可以是访问顺序(默认实现是按插入顺序排序的)。
LinkedHashMap采用的hash算法和HashMap相同,但是它重新定义了Entry。LinkedHashMap中的Entry继承了HashMap.Node,但是增加了两个指针before和after,它们分别用于维护双向链接列表(注意:next用于维护HashMap各个Node的连接顺序,before、after用于维护Entry插入的先后顺序)。LinkedHashMap区别于HashMap最大的一个不同点就是前者是有序的,而后者是无序的。
LinkedHashMap的构造函数都是在HashMap的构造函数基础之上实现的,如下:
/**
* Constructs an empty insertion-ordered <tt>LinkedHashMap</tt> instance
* with the specified initial capacity and load factor.
*
* @param initialCapacity the initial capacity
* @param loadFactor the load factor
* @throws IllegalArgumentException if the initial capacity is negative
* or the load factor is nonpositive
*/
public LinkedHashMap(int initialCapacity, float loadFactor) {
super(initialCapacity, loadFactor);
accessOrder = false;
}
/**
* Constructs an empty insertion-ordered <tt>LinkedHashMap</tt> instance
* with the specified initial capacity and a default load factor (0.75).
*
* @param initialCapacity the initial capacity
* @throws IllegalArgumentException if the initial capacity is negative
*/
public LinkedHashMap(int initialCapacity) {
super(initialCapacity);
accessOrder = false;
}
/**
* Constructs an empty insertion-ordered <tt>LinkedHashMap</tt> instance
* with the default initial capacity (16) and load factor (0.75).
*/
public LinkedHashMap() {
super();
accessOrder = false;
}
/**
* Constructs an insertion-ordered <tt>LinkedHashMap</tt> instance with
* the same mappings as the specified map. The <tt>LinkedHashMap</tt>
* instance is created with a default load factor (0.75) and an initial
* capacity sufficient to hold the mappings in the specified map.
*
* @param m the map whose mappings are to be placed in this map
* @throws NullPointerException if the specified map is null
*/
public LinkedHashMap(Map<? extends K, ? extends V> m) {
super();
accessOrder = false;
putMapEntries(m, false);
}
/**
* Constructs an empty <tt>LinkedHashMap</tt> instance with the
* specified initial capacity, load factor and ordering mode.
*
* @param initialCapacity the initial capacity
* @param loadFactor the load factor
* @param accessOrder the ordering mode - <tt>true</tt> for
* access-order, <tt>false</tt> for insertion-order
* @throws IllegalArgumentException if the initial capacity is negative
* or the load factor is nonpositive
*/
public LinkedHashMap(int initialCapacity,
float loadFactor,
boolean accessOrder) {
super(initialCapacity, loadFactor);
this.accessOrder = accessOrder;
}
以上就是今天的所有讲解,有些东西并没有讲的很详细,大家如果有什么概念不了解,可以自行上网搜索一下,谢谢。