集合工具类之List特点和实现类的详解
Java集合框架的由来:
其实在Java2之前,Java是没有完整的集合框架的。它只有一些简单的可以自扩建的容器类,比如Vector,Stack,Hashtable等。
为什么存在容器类:容器类(集合类)可以存储多个数据,既然数组可以存储多个数据,为什么需要定义容器类呢?
2、在N个地方需要存储多个数据,都得专门去编写数组的操作方法,如此一来,没有体现DRY原则,代码和功能重复-->封装思想;
3、既然每一个人都要使用到数组类,但是不同的人定义的类名和方法是不同的,实现细节也是参差不齐的,SUN公司就自己定义好了容器类,每一个开发者只管调用即可。
什么是集合框架:
尽管这些容器类非常好用,但是却不能集中和统一管理。集合框架是为表示和操作集合而规定的一种统一的标准的体系结构。任何集合框架都包含三大快内容:
对外的接口、接口的实现和对集合运算的算法。(底层对应着某一种数据结构和算法)
为什么需要集合框架:
1、提供功能的复用;
2、使得程序员专注于业务开发,而不是数据结构和算法。
常用的框架接口规范:
Set(集):集合中的对象不安特定的方式排序,不允许元素重复;
List(列表):集合中的对象按照索引位置排序,允许元素重复;
Map(映射):集合中每一个元素都包含一对key和value对象,不允许key对象重复,value对象可以重复。
看过Vector源码之后,会发现Vector类中有一个Object[]类型数组。
2、我们发现该数组的元素类型是Object类型,意味着集合中只能存储任意类型的对象。
集合中只能存储对象,不能存储基本数据类型的值。
在Java5之前,必须对基本数据类型手动装箱。
如:v.addElement(Integer.valueOf(123));
java5开始支持自动装箱操作,
代码如:v.addElement(123);其实底层依旧是手动装箱;
3、集合类中存储的对象,都存储的是对象的引用。
ArrayList类是Java集合框架出现之后用来取代Vector类的:
二者底层原理都是基于数组的算法,一模一样。
----------------------------------
区别:
Vector:所有的方法都使用了synchronized修饰符。(线程安全,但性能较低,适用于多线程环境)
ArrayList:所有的方法都没有使用了synchronized修饰符。(线程不安全,但性能较高)
但是即使以后在多线程环境下,我们也不使用Vector类:
ArrayList list = Collections.synchronizedList(new ArrayList(…));
阅读源代码会发现,Vector类和ArrayList的源代码差异有点大(从设计上考虑的)
有的时候某个方法需要返回一个ArrayList对象:
但是在该方法中,如果一个元素都没有查询到,我们不会返回Null,我们会返回一个空寂对象(没有元素的集合)。
public ArrayList getAll(){
//return Collections.emptyList();//最好的方式
return new ArrayList();//但是很多人最直观,最简单选用的方式是这种。
}
Object[] elementData = new Object[]{};
在第一次调用add方法的时候,才会重新去初始化数组。
LinkedList类是双向链表,单向队列,双向队列,栈的实现类:
LinkedList类实现单向队列和双向队列的接口,自身提高了栈和链表的操作方法。
在LinkedList类中存在很多方法,但是功能都是相同的,LinkedList表示了很多数据结构的实现,每一种数据结构的操作名字不同。
LinkedList类是线程不安全的类,在多线程环境下所保证线程安全:
ArrayList list = Collections.synchronizedList(new LinkedList (…));
无论是链表还是队列,都特别擅长操作头和尾的节点,在LinkedList中大多数方法都是xxFirst/xxLast的
在LinkedList中存在Object get(int index),表示根据索引位置获取相应的元素。
链表没有索引的概念,本不应该有索引,但是从Java2开始存在了集合框架,让LinkedList类作为List接口的实现类,List中提供了该根据索引查询元素的方法,LinkedList内部类提供了一个变量来当做索引。
该方法要少用,因为LinkedList不擅长做查询操作,擅长做保存和删除操作。
List实现类特点和性能分析:
三者共同的特点(共同遵循的规则):
1) 允许元素重复;
2) 记录元素的添加顺序。
Vector类:底层采用数组结构算法,方法都使用了synchronized修饰,线程安全,但性能相对于ArrayList较低;(不用)
ArrayList类:底层采用数组结构算法,方法都没有使用synchronized修饰,线程不安全,但性能相对于Vector较高;
LinkedList类:底层采用了双向链表结构算法,方法没有使用synchronized修饰,线程不安全。
线程安全:如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程时运行的结果是一样的,而且其他变量的值也和预期的是一样的,说明线程就是安全的。
数组结构算法:插入和删除操作速度低,查询和更改较快;
链表结构算法:没有越界和扩容的概念,插入和删除操作速度快,查询和更改较慢。
在开发中使用ArrayList较多,根据具体的需求环境来做选择。
其实在Java2之前,Java是没有完整的集合框架的。它只有一些简单的可以自扩建的容器类,比如Vector,Stack,Hashtable等。
为什么存在容器类:容器类(集合类)可以存储多个数据,既然数组可以存储多个数据,为什么需要定义容器类呢?
数组的弊端:
1、长度是不可变的,一旦数组初始化之后,长度是固定的;2、在N个地方需要存储多个数据,都得专门去编写数组的操作方法,如此一来,没有体现DRY原则,代码和功能重复-->封装思想;
3、既然每一个人都要使用到数组类,但是不同的人定义的类名和方法是不同的,实现细节也是参差不齐的,SUN公司就自己定义好了容器类,每一个开发者只管调用即可。
什么是集合框架:
尽管这些容器类非常好用,但是却不能集中和统一管理。集合框架是为表示和操作集合而规定的一种统一的标准的体系结构。任何集合框架都包含三大快内容:
对外的接口、接口的实现和对集合运算的算法。(底层对应着某一种数据结构和算法)
为什么需要集合框架:
1、提供功能的复用;
2、使得程序员专注于业务开发,而不是数据结构和算法。
常用的框架接口规范:
集合中存储的对象,称之为集合元素。
Set(集):集合中的对象不安特定的方式排序,不允许元素重复;
List(列表):集合中的对象按照索引位置排序,允许元素重复;
Map(映射):集合中每一个元素都包含一对key和value对象,不允许key对象重复,value对象可以重复。
来看一下集合类的关系图
看过Vector源码之后,会发现Vector类中有一个Object[]类型数组。
protected Object[] elementData;
2、我们发现该数组的元素类型是Object类型,意味着集合中只能存储任意类型的对象。
集合中只能存储对象,不能存储基本数据类型的值。
在Java5之前,必须对基本数据类型手动装箱。
如:v.addElement(Integer.valueOf(123));
java5开始支持自动装箱操作,
代码如:v.addElement(123);其实底层依旧是手动装箱;
3、集合类中存储的对象,都存储的是对象的引用。
ArrayList类是Java集合框架出现之后用来取代Vector类的:
二者底层原理都是基于数组的算法,一模一样。
----------------------------------
区别:
Vector:所有的方法都使用了synchronized修饰符。(线程安全,但性能较低,适用于多线程环境)
ArrayList:所有的方法都没有使用了synchronized修饰符。(线程不安全,但性能较高)
但是即使以后在多线程环境下,我们也不使用Vector类:
ArrayList list = Collections.synchronizedList(new ArrayList(…));
阅读源代码会发现,Vector类和ArrayList的源代码差异有点大(从设计上考虑的)
有的时候某个方法需要返回一个ArrayList对象:
但是在该方法中,如果一个元素都没有查询到,我们不会返回Null,我们会返回一个空寂对象(没有元素的集合)。
public ArrayList getAll(){
//return Collections.emptyList();//最好的方式
return new ArrayList();//但是很多人最直观,最简单选用的方式是这种。
}
在Java7之前,即使使用new ArrayList()创建对象,一个元素都不存储,但是在堆空间依然初始化了长度为10的Object数组,其实没必要。
Object[] elementData = new Object[]{};
在第一次调用add方法的时候,才会重新去初始化数组。
LinkedList类是双向链表,单向队列,双向队列,栈的实现类:
LinkedList类实现单向队列和双向队列的接口,自身提高了栈和链表的操作方法。
在LinkedList类中存在很多方法,但是功能都是相同的,LinkedList表示了很多数据结构的实现,每一种数据结构的操作名字不同。
LinkedList类是线程不安全的类,在多线程环境下所保证线程安全:
ArrayList list = Collections.synchronizedList(new LinkedList (…));
无论是链表还是队列,都特别擅长操作头和尾的节点,在LinkedList中大多数方法都是xxFirst/xxLast的
在LinkedList中存在Object get(int index),表示根据索引位置获取相应的元素。
链表没有索引的概念,本不应该有索引,但是从Java2开始存在了集合框架,让LinkedList类作为List接口的实现类,List中提供了该根据索引查询元素的方法,LinkedList内部类提供了一个变量来当做索引。
该方法要少用,因为LinkedList不擅长做查询操作,擅长做保存和删除操作。
List实现类特点和性能分析:
三者共同的特点(共同遵循的规则):
1) 允许元素重复;
2) 记录元素的添加顺序。
Vector类:底层采用数组结构算法,方法都使用了synchronized修饰,线程安全,但性能相对于ArrayList较低;(不用)
ArrayList类:底层采用数组结构算法,方法都没有使用synchronized修饰,线程不安全,但性能相对于Vector较高;
LinkedList类:底层采用了双向链表结构算法,方法没有使用synchronized修饰,线程不安全。
线程安全:如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程时运行的结果是一样的,而且其他变量的值也和预期的是一样的,说明线程就是安全的。
数组结构算法:插入和删除操作速度低,查询和更改较快;
链表结构算法:没有越界和扩容的概念,插入和删除操作速度快,查询和更改较慢。
对List的简单说明:
1、Vector类打死不要用,即使要用也选择ArrayList类;
2、如果删除和插入操作频繁,应该选择LinkedList类;
3、如果查询操作频繁,应该使用ArrayList类;在开发中使用ArrayList较多,根据具体的需求环境来做选择。