Java集合框架的讲解
下面要开始java中相关集合框架的学习啦。
Are you ready?Let's Go~~
今天要讲解的Java中的集合框架。
1) 首先查看jdk中Collection类的源码后会发现如下内容:
1
2
3
4
5
6
7
... * @see AbstractCollection
* @since 1.2
*/
public interface Collection<e> extends Iterable<e> {
// Query Operations
</e></e>
通过查看可以发现Collection是一个接口类,其继承了java迭代接口Iterable。
众所周知在我们使用Java中的类的存储的时候经常会使用一些容器,链表的概念,本文将彻底帮您弄清链表的各种概念和模型!!!!
注意理解哦~~~ 大致框架如下:
Collection接口有两个主要的子接口List和Set,注意Map不是Collection的子接口哦这个要牢记。
Collection中可以存储的元素间无序,可以重复组各 自独立的元素, 即其内的每个位置仅持有一个元素,同时允许有多个null元素对象。
Collection接口中的方法如下:
1)List接口
List接口对Collection进行了简单的扩充
查看List接口的源码会发现:
1
2
3
4
5
6
7
8
9
10
11
12
13
...<br> * @see AbstractList
* @see AbstractSequentialList
* @since 1.2
*/
public interface List<E> extends Collection<E> {
// Query Operations
/**
* Returns the number of elements in this list. If this list contains
* more than <tt>Integer.MAX_VALUE</tt> elements, returns
* <tt>Integer.MAX_VALUE</tt>.
<br> ...
这里也就知道为什么Collection接口时List接口的父接口了吧。
List接口中的元素的特点为:
List中存储的元素实现类排序,而且可以重复的存储相关元素。
同时List接口又有两个常用的实现类ArrayList和LinkedList
1)ArrayList:
ArrayList数组线性表的特点为:类似数组的形式进行存储,因此它的随机访问速度极快。
ArrayList数组线性表的缺点为:不适合于在线性表中间需要频繁进行插入和删除操作。因为每次插入和删除都需要移动数组中的元素。
可以这样理解ArrayList就是基于数组的一个线性表,只不过数组的长度可以动态改变而已。
对于ArrayList的详细使用信息以及创建的过程可以查看jdk中ArrayList的源码,这里不做过多的讲解。
对于使用ArrayList的开发者而言,下面几点内容一定要注意啦,尤其找工作面试的时候经常会被问到。
注意啦!!!!!!!!
a.如果在初始化ArrayList的时候没有指定初始化长度的话,默认的长度为10.
1
2
3
4
5
6
/**
* Constructs an empty list with an initial capacity of ten.
*/
public ArrayList() {
this(10);
}
b.ArrayList在增加新元素的时候如果超过了原始的容量的话,ArrayList扩容ensureCapacity的方案为“原始容量*3/2+1"哦。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
* Increases the capacity of this <tt>ArrayList</tt> instance, if
* necessary, to ensure that it can hold at least the number of elements
* specified by the minimum capacity argument.
*
* @param minCapacity the desired minimum capacity
*/
public void ensureCapacity(int minCapacity) {
modCount++;
int oldCapacity = elementData.length;
if (minCapacity > oldCapacity) {
Object oldData[] = elementData;
int newCapacity = (oldCapacity * 3)/2 + 1;
if (newCapacity < minCapacity)
newCapacity = minCapacity;
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
}
}
c.ArrayList是线程不安全的,在多线程的情况下不要使用。
如果一定在多线程使用List的,您可以使用Vector,因为Vector和ArrayList基本一致,区别在于Vector中的绝大部分方法都
使用了同步关键字修饰,这样在多线程的情况下不会出现并发错误哦,还有就是它们的扩容方案不同,ArrayList是通过原始
容量*3/2+1,而Vector是允许设置默认的增长长度,Vector的默认扩容方式为原来的2倍。
切记Vector是ArrayList的多线程的一个替代品。
d.ArrayList实现遍历的几种方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
package com.yonyou.test;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
* 测试类
* @author 小浩
* @创建日期 2015-3-2
*/
public class Test{
public static void main(String[] args) {
List<String> list=new ArrayList<String>();
list.add("Hello");
list.add("World");
list.add("HAHAHAHA");
//第一种遍历方法使用foreach遍历List
for (String str : list) { //也可以改写for(int i=0;i<list.size();i++)这种形式
System.out.println(str);
}
//第二种遍历,把链表变为数组相关的内容进行遍历
String[] strArray=new String[list.size()];
list.toArray(strArray);
for(int i=0;i<strArray.length;i++) //这里也可以改写为foreach(String str:strArray)这种形式
{
System.out.println(strArray[i]);
}
//第三种遍历 使用迭代器进行相关遍历
Iterator<String> ite=list.iterator();
while(ite.hasNext())
{
System.out.println(ite.next());
}
}
}
尼玛,以上四点面试经常会被问到的。到时候死翘翘别说哥没告诉你。
2)LinkedList
LinkedList的链式线性表的特点为: 适合于在链表中间需要频繁进行插入和删除操作。
LinkedList的链式线性表的缺点为: 随机访问速度较慢。查找一个元素需要从头开始一个一个的找。速度你懂的。
可以这样理解LinkedList就是一种双向循环链表的链式线性表,只不过存储的结构使用的是链式表而已。
对于LinkedList的详细使用信息以及创建的过程可以查看jdk中LinkedList的源码,这里不做过多的讲解。
对于使用LinkedList的开发者而言,下面几点内容一定要注意啦,尤其找工作面试的过程时候经常会被问到。
注意啦!!!!!!!!
a.LinkedList和ArrayList的区别和联系
ArrayList数组线性表的特点为:类似数组的形式进行存储,因此它的随机访问速度极快。
ArrayList数组线性表的缺点为:不适合于在线性表中间需要频繁进行插入和删除操作。因为每次插入和删除都需要移动数组中的元素。
LinkedList的链式线性表的特点为: 适合于在链表中间需要频繁进行插入和删除操作。
LinkedList的链式线性表的缺点为: 随机访问速度较慢。查找一个元素需要从头开始一个一个的找。速度你懂的。
b.LinkedList的内部实现
对于这个问题,你最好看一下jdk中LinkedList的源码。这样你会醍醐灌顶的。
这里我大致说一下:
LinkedList的内部是基于双向循环链表的结构来实现的。在LinkedList中有一个类似于C语言中结构体的Entry内部类。
在Entry的内部类中包含了前一个元素的地址引用和后一个元素的地址引用类似于c语言中指针。
c.LinkedList不是线程安全的
注意LinkedList和ArrayList一样也不是线程安全的,如果在对线程下面访问可以自己重写LinkedList
然后在需要同步的方法上面加上同步关键字synchronized
d.LinkedList的遍历方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
package com.yonyou.test;
import java.util.LinkedList;
import java.util.List;
/**
* 测试类
* @author 小浩
* @创建日期 2015-3-2
*/
public class Test{
public static void main(String[] args) {
List<String> list=new LinkedList<String>();
list.add("Hello");
list.add("World");
list.add("龙不吟,虎不啸");
//LinkedList遍历的第一种方式使用数组的方式
String[] strArray=new String[list.size()];
list.toArray(strArray);
for(String str:strArray)
{
System.out.println(str);
}
//LinkedList遍历的第二种方式
for(String str:list)
{
System.out.println(str);
}
//至于还是否有其它遍历方式,我没查,感兴趣自己研究研究
}
}
e.LinkedList可以被当做堆栈来使用
由于LinkedList实现了接口Dueue,所以LinkedList可以被当做堆栈来使用,这个你自己研究吧。
2)Set接口
Set接口也是Collection接口的一个常用子接口。
查看Set接口的源码你会发现:
1
2
3
4
5
6
7
8
9
10
* @see Collections#EMPTY_SET
* @since 1.2
*/
public interface Set<E> extends Collection<E> {
// Query Operations
/**
* Returns the number of elements in this set (its cardinality). If this
* set contains more than <tt>Integer.MAX_VALUE</tt> elements, returns
这里就自然而然的知道Set接口是Collection接口的子接口了吧。
Set接口区别于List接口的特点在于:
Set中的元素实现了不重复,有点象集合的概念,无序,不允许有重复的元素,最多允许有一个null元素对象。
需要注意的是:虽然Set中元素没有顺序,但是元素在set中的位置是有由该元素的HashCode决定的,其具体位置其实是固定的。
查看jdk的源码会发现下面的内容
1
2
3
4
5
6
7
8
9
10
11
...<br> * @see Collections#EMPTY_SET
* @since 1.2
*/
public interface Set<E> extends Collection<E> {
// Query Operations
/**
* Returns the number of elements in this set (its cardinality). If this
* set contains more than <tt>Integer.MAX_VALUE</tt> elements, returns
<br> ...
在这里也会看到set接口时Collection接口的子接口吧~哈
此外需要说明一点,在set接口中的不重复是由特殊要求的。
举一个例子:对象A和对象B,本来是不同的两个对象,正常情况下它们是能够放入到Set里面的,但是
如果对象A和B的都重写了hashcode和equals方法,并且重写后的hashcode和equals方法是相同的话。那么A和B是不能同时放入到
Set集合中去的,也就是Set集合中的去重和hashcode与equals方法直接相关。
为了更好的理解,请看下面的例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22