一.Vector
-
JDK2之前(在集合框架之前),要存储多个数据,此时存在一个叫Vector类.
Vector类的底层其实就是一个Object数组,Vector类中的方法时支持同步(方法使用synchronized修饰)的. -
Vector类设计原理,查看源代码
-
Vector类存储原理
通过源码分析,发现在Vector类中有一个Object()[]类型数组.
protected Ojbect[] elementDate;- 表面上把数据存储到Vector对象中,其实底层依然是把数据存储到Object数组中
- 我们发现该数组元素类型是Object类型,意味着集合中只能存储任意类型的对象.
集合中只能存储对象,不能存储基本数据类型的值
在Java5之前,必须对基本数据类型手动装箱.
v.addElement(Integer.valueOf(123));
从Java5开始支持自动装箱操作,代码
v.addElement(123);
其实底层依然是手动装箱
注意:修改项目的编译级别到Java5或者Java5以上.
![image][Java5]
3. 集合类中存储的对象,都存储对象的引用.而不是对象本身
![image][cite]
新建类VectorDemo
//Vector类的演示
public class VectorDemo {
public static void main(String[] args) {
Vector vector = new Vector();
vector.addElement("a");
vector.addElement("AA");
vector.addElement(12);
StringBuilder sb = new StringBuilder();
sb.append("last");
vector.addElement(sb);
System.out.println(vector.toString());
sb.append("com");
System.out.println(vector.toString());
}
}
-
集合类的操作方法:
-
常用方法:
-
增加:
- boolean add(Object e): 将指定元素添加到此向量的末尾
- void add(int index,Object element):在此向量的指定位置插入指定的元素
- boolean addAll(Collection c):把c集合中的元素添加到当前集合对象中
![image][method]
-
删除:
- Object remove(int index):删除指定索引位置的元素,并返回删除之后的元素
- boolean remove(Object o):删除指定的元素.
- boolean removeAll(Collection c):从此集合中移除包含在指定集合c中的所有元素
- boolean retainAll(Collection c):在此集合中仅仅保留包含在指定集合c中的元素
-
修改:
- Object set(int index,Object element):修改当前集合中指定索引位置的元素
返回被替换的旧元素
- Object set(int index,Object element):修改当前集合中指定索引位置的元素
-
查询:
- int size():返回当前集合中存储几个元素
- boolean isEmpty():判断当前集合中元素个数是否为0
- Object get(int index):查询指定索引位置的元素
- Object[] toArray():把集合对象转换为Object数组
新建类VectorMethodDemo
public class VectorMethodDemo {
public static void main(String[] args) {
//testAdd();
//testDelet();
//testUpdate();
testQuery();
}
//查询
private static void testQuery() {
Vector v = new Vector();
v.add("A");
v.add("B");
v.add("C");
v.add("C");
v.add("F");
System.out.println(v.toString());
System.out.println(v.size());
System.out.println(v.isEmpty());
System.out.println(v.get(2));
Object[] o = v.toArray();
System.out.println(Arrays.toString(o));
}
//更新
private static void testUpdate() {
Vector v = new Vector();
v.add("A");
v.add("B");
v.add("C");
v.add("C");
v.add("F");
v.set(3, "D");
System.out.println(v.toString());
}
//删除
private static void testDelet() {
Vector v = new Vector();
v.add("A");
v.add("B");
v.add("C");
v.add("C");
v.add("F");
v.remove(0);
Vector v1 = new Vector();
v1.add("C");
v1.add("B");
System.out.println(v.toString());
v.remove("A");
//v.removeAll(v1);
v.retainAll(v1);
System.out.println(v.toString());
}
//添加
private static void testAdd() {
Vector v = new Vector();
v.add("A");
v.add("B");
v.add("C");
v.add(1, "F");
System.out.println(v.toString());
Vector v1 = new Vector();
v1.add("A");
v1.add("B");
v1.add("C");
v.add(1, v1);
System.out.println(v.toString());
v.addAll(1, v1);
System.out.println(v.toString());
}
}
二.栈(Stack)
- 数据结构的一种,存储特点Last in First Out
- Stack 类表示后进先出(LIFO)的对象栈
官方建议:使用栈尽量使用ArrayDeque:
Deque 接口及其实现提供了 LIFO 堆栈操作的更完整和更一致的 set,应该优先使用此 set,而非此类。例如:
Deque<Integer> stack = new ArrayDeque<Integer>();
新建类StackDemo
public class StackDemo {
public static void main(String[] args) {
Stack s = new Stack();
s.push("A");
s.push("B");
s.push("C");
s.push("D");
System.out.println(s.toString());
System.out.println(s.peek());
s.pop();
System.out.println(s.peek());
ArrayDeque as = new ArrayDeque();
as.push("A");
as.push("B");
as.push("C");
as.push("D");
System.out.println(as.toString());
System.out.println(as.peek());
as.pop();
System.out.println(as.peek());
}
}
三.ArrayList类
- 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数据,没有必要.
从Java7开始优化这个设计,
new ArrayList,其实底层创建的使用一个空数组.
Object[] elementDate = new Object[]{};
在第一次调用add方法的时候,才会从新去初始化数组.
四.LinkedList
-
LinkedList类是双向链表,单向队列,双向队列的实现类
-
LinkedList类实现单向队列和双向队列的接口,自身提高了栈操作的方法,链表操作的方法.
-
LinkedList类中存在很多方法,但是功能都是相同的,LinkedList表示了多种数据结构的实现,每一种数据
结构的操作名字都不同.
![image][table1]
![image][table2]
![image][table3]
![image][table4]
- LinkedList类是线程不安全的类,在多行程环境下,下面保证线程的安全
List list = Collections.synchronizedList(new LinkedList(...));
-
面试题:编写一个双向链表
无论是链表还是队列,都特别擅长操作头和尾的节点
在LinkedList中大多数方法都是xxFirst/xxLast -
在LinkList中存在Object get(int index),表示根据索引位置获取对应的元素.
链表没有索引的概念,但是从Java2开始,存在了集合框架,让LinkedList类作为List接口的实现类. -
List类中提供了该根据索引查询元素的方法,LinkedList内部类提供了一个变量来当做索引
该方法少用,因为LinkedList不擅长查询操作.
新建类LinkedListDemo
public class LinkedlistDemo {
public static void main(String[] args) {
LinkedList ll = new LinkedList();
ll.addFirst("H");
ll.addFirst("K");
ll.addLast("U");
System.out.println(ll.toString());
System.out.println(ll.get(2));
System.out.println(ll.indexOf("K"));
}
}
五.Java集合框架-重构设计
![image][Java1]
![image][Java2]
![image][Java3]
- 根据Vector类,ArrayList类,LinkedList类,所具有的存储特点以及拥有的方法入手,发现共性就往上抽取.
共同特点:- 允许元素重复的
- 会记录先后添加的顺序
- 共同方法:如上图
- 根据他们的特点,可以指定规范:
遵循该规范的实现类,无论底层算法如何,都必须保证允许元素重复和保证添加先后顺序. - 给该规范起名:List
在Java中规范使用接口表示
![image][Iterable]
六.List类特点和性能分析
![image][ListClass]
- 面向接口编程:
接口类型 变量 = new 实现类();
List list = new ArrayList();
-
三者共同的特点(共同遵循的规范)
- 允许元素重复
- 记录元素的先后添加顺序
-
Vector类:底层才有数组结构算法,方法都使用synchronized修饰,线程安全,但是性能相对于ArrayList较低
-
ArrayList类:底层才有数组结构算法,方法没有使用synchronized修饰,线程不安全,性能相对于Vector较高
-
现在ArrayList几乎已经取代了Vector
-
为了保证ArrayList线程安全:
List list = new Collections.synchronizedList(new ArrayList(....));
-
LinkedList类:底层才有双向链表结构算法,方法没有使用synchronized修饰,线程不安全
-
数组结构算法和双向结构算法的性能问题:
-
数组结构算法:插入和删除操作速度低,查询和更改较快
-
链表结构算法:插入和删除操作速度快,查询和更改较慢
-
使用选择:
-
不使用Vector类,
-
如果删除和插入操作频繁,应该使用LinkedList类
-
如果查询操作频繁,应该使用ArrayList类