一、Collection接口
首先,让我们来看一下Collection接口的继承体系
(一)Collection的常用功能
1. 添加功能booleanadd(E e)
添加一个元素booleanaddAll(Collection c)
添加一批元素2. 删除功能booleanremove(Object o)
删除一个元素3. 判断功能booleancontains(Object o)
判断集合是否包含指定的元素booleanisEmpty()
判断集合是否为空(集合中没有元素)4. 获取功能intsize()
获取集合的长度5. 转换功能
Object[] toArray()
把集合转换为数组
(二)遍历集合的方式
1.普通的for循环【必须要有索引,可以修改元素】
import java.util.*;public classtest{public static voidmain(String[] args) {
ArrayList list = new ArrayList();
list.add("Hello");
list.add("Java");
list.add("World");for (int i = 0; i < list.size(); i++){
String s=(String) list.get(i);
System.out.println(s);
}
}
}
2.迭代器遍历【任何集合都可以遍历,只能获取元素】
import java.util.*;public classtest{public static voidmain(String[] args) {
Collection c = new ArrayList();
c.add("Hello");
c.add("Java");
c.add("World");//获取迭代器对象
Iterator it =c.iterator();//hasNext()判断是否有下一个元素,如果有就用next()获取
while(it.hasNext()){//获取下一个元素
String s =it.next();
System.out.println(s);
}
}
}
3.高级for循环【就是迭代器的简化方式】
import java.util.*;public classtest{public static voidmain(String[] args) {
Collection c = new ArrayList();
c.add("Hello");
c.add("Java");
c.add("World");//高级for遍历集合
for(String s : c){
System.out.println(s);
}int[] arr = {1, 2, 3, 4, 5};//高级for遍历数组
for (inta : arr){
System.out.println(a);
}
}
}
(三)常见的数据结构
数据结构指的是数据的组存储方式,不同的数据结构有不同的特点。
1. 数组结构(ArrayList底层结构)
查询快,增删慢
2. 链表结构(LinkedList底层结构)
查询慢,增删快
3. 栈和队列
栈:先进后出(子弹夹,杯子)
队列:先进先出(排队,管子)
二、List接口
List集合类中元素有序、且可重复,集合中的每个元素都有其对应的顺序索引。
List容器中的元素都对应一个整数型的序号记载其在容器中的位置,可以根据序号存取容器中的元素。
JDK API中List接口的实现类常用的有:ArrayList、LinkList和Vector。
List集合里添加了一些根据索引来操作集合元素的方法
1.add(intindex, Object ele)2.boolean addAll(intindex, Collection eles)3.Object get(intindex)4.intindexOf(Object obj)5.intlastIndexOf(Object obj)6.Object remove(intindex)7.Object set(intindex, Object ele)8.List subList(int fromIndex, int toIndex)
(一)ArrayList
ArrayList是List接口的典型实现类,本质上,ArrayList是对象引用的一个变长数组。
ArrayList是List接口的可变数组的实现。实现了所有可选列表操作,并允许包括null在内的所有元素。除了实现List接口外,此类还提供了一些方法来操作内部用来存储列表的数组的大小。
每个ArrayList实例都有一个初始容量,该容量用来储存列表元素的数组大小。默认初始容量为10。
ArrayList底层采用数组实现。数组都有一个重大的缺陷,这就是从数组的中间位置删除一个元素要付出很大的代价,其原因是数组中处于被删除元素之后的所有元素都要向数组的前端移动。在数组中间位置插入一个元素也是如此(数据的copy)。
注:Arrays.asList(…) 方法返回的 List 集合既不是 ArrayList 实例,也不是 Vector 实例。 Arrays.asList(…)返回值是一个固定长度的 List 集合。
1.ArrayList的存取实现
存储:
ArrayList提供了一下添加元素的方法
set(int index, E element)、
add(E e)、
add(int index, E element)、
addAll(Collection extends E> c)、
addAll(inr index, Collection extends E> c)
add(E element)方法,将指定的元素添加到列表的尾部
import java.util.*;public classtest{public static voidmain(String[] args) {
ArrayList list = new ArrayList();
System.out.println(list);
list.add("Java");
System.out.println(list);
}
}
add(int index, E element)方法,将指定的元素插入此列表的指定位置,如果当前位置有元素,则向右移动当前位于该位置的元素以及所有后续元素(将其索引值加1)
import java.util.*;public classtest{public static voidmain(String[] args) {
ArrayList list = new ArrayList();
list.add("hello");
list.add("world");
list.add("leslie");
System.out.println(list);
list.add(1,"Java");
System.out.println(list);
}
}
set(int index, E element)方法,替换数组中已经存在的元素内容。
import java.util.*;public classtest{public static voidmain(String[] args) {
ArrayList list = new ArrayList();
list.add("hello");
list.add("world");
list.add("leslie");
System.out.println(list);
list.set(1,"Java");
System.out.println(list);
}
}
addAll(Collection extends E> c)方法,按照指定Collection的迭代器所返回的元素顺序,将该Collection中的所有元素添加到此列表的尾部。
import java.util.*;public classtest{public static voidmain(String[] args) {
List list = new ArrayList();
list.add("hello");
list.add("world");
list.add("leslie");
System.out.println(list);
List list_ad = new ArrayList();
list_ad.add("are you ok ?");//将list中的全部元素添加到list_ad中
System.out.println("添加是否成功:" +list_ad.addAll(list));//通过循环输出列表中的内容
for (int i = 0; i < list_ad.size(); i++){
System.out.println(i+ ":" +list_ad.get(i));
}
}
}
addAll(int index, Collection extends E> c)方法,从指定的位置开始,将指定collection中的所有元素插入到此列表中
import java.util.*;public classtest{public static voidmain(String[] args) {
List list = new ArrayList();
list.add("hello");
list.add("world");
list.add("leslie");
System.out.println(list);
List list_ad = new ArrayList();
list_ad.add("are you ready ?");
list_ad.add("are you ok ?");//将list中的全部元素添加到list_ad中
System.out.println("添加是否成功:" + list_ad.addAll(1,list));//通过循环输出列表中的内容
for (int i = 0; i < list_ad.size(); i++){
System.out.println(i+ ":" +list_ad.get(i));
}
}
}
读取
get(int index)方法,获取指定位置上的元素
import java.util.*;public classtest{public static voidmain(String[] args) {
List list = new ArrayList();
list.add("hello");
list.add("world");
list.add("leslie");
System.out.println(list);
System.out.println(list.get(1));
}
}
总结:
ArrayLlist内部是由数组来实现的。在存放数据的数组长度不够时,会进行扩容,即增加数组长度。扩展为原来的1.5倍。
由于是数组来实现,所以,优点是查找元素很快。可以通过下标查找元素,查找效率高。缺点是每次添加和删除元素都会进行大量的数组元素移动。长度不够会扩容。效率底下。
ArrayList每次的增、删、改操作都伴随着数组的复制和元素的移动。这意味着新的内存空间的开辟。
(二)LinkedList
LinkedList其实也就是我们在数据结构中的链表,这种数据结构有这样的特性:
分配内存空间不是必须是连续的;
插入、删除操作很快,只要修改前后指针就OK了,时间复杂度为O(1);
访问比较慢,必须得从第一个元素开始遍历,时间复杂度为O(n);
在Java中,LinkedList提供了丰富的方法,可以模拟链式队列,链式堆栈等数据结构,为用户带来了极大的方便,下面看看这些方法的用法:
add
booleanadd(E e):在链表后添加一个元素,如果成功,返回true,否则返回false;voidaddFirst(E e):在链表头部插入一个元素;
addLast(E e):在链表尾部添加一个元素;void add(int index, E element):在指定位置插入一个元素。
示例代码
import java.util.*;public classtest{public static voidmain(String[] args) {
LinkedList linkList = new LinkedList<>();
linkList.add("first");
linkList.add("second");
linkList.add("third");
System.out.println(linkList);
linkList.addFirst("addFirst");
System.out.println(linkList);
linkList.addLast("addLast");
System.out.println(linkList);
linkList.add(2, "addByIndex");
System.out.println(linkList);
}
}
输出:
remove
E remove();移除链表中第一个元素;booleanremove(Object o):移除链表中指定的元素;
E remove(intindex):移除链表中指定位置的元素;
E removeFirst():移除链表中第一个元素,与remove类似;
E removeLast():移除链表中最后一个元素;booleanremoveFirstOccurrence(Object o):移除链表中第一次出现所在位置的元素;boolean removeLastOccurrence(Object o):移除链表中最后一次出现所在位置的元素;
示例代码:
import java.util.*;public classtest{public static voidmain(String[] args) {
LinkedList linkedList = new LinkedList<>();
linkedList.add("first");
linkedList.add("second");
linkedList.add("second");
linkedList.add("third");
linkedList.add("four");
linkedList.add("five");
System.out.println(linkedList);
linkedList.remove();
System.out.println("remove: " +linkedList);
linkedList.remove("second");
System.out.println("remove(Object): " +linkedList);
linkedList.remove("six");
System.out.println("remove(Object) not exist: " +linkedList);
linkedList.remove(2);
System.out.println("remove(index): " +linkedList);
linkedList.removeFirst();
System.out.println("removeFirst: " +linkedList);
linkedList.removeLast();
System.out.println("removeLast:" +linkedList);
System.out.println("----------------------------------");
linkedList.clear();
linkedList.add("first");
linkedList.add("second");
linkedList.add("first");
linkedList.add("third");
linkedList.add("first");
linkedList.add("five");
System.out.println(linkedList);
linkedList.removeFirstOccurrence("first");
System.out.println("removeFirstOccurrence: " +linkedList);
linkedList.removeLastOccurrence("first");
System.out.println("removeLastOccurrence: " +linkedList);
}
}
输出:
get
E get(intindex):按照下边获取元素;
E getFirst():获取第一个元素;
E getLast():获取最后一个元素;
示例代码
import java.util.*;public classtest{public static voidmain(String[] args) {
LinkedList linkedList = new LinkedList<>();
linkedList.add("first");
linkedList.add("second");
linkedList.add("second");
linkedList.add("third");
linkedList.add("four");
linkedList.add("five");
System.out.println(linkedList);
System.out.println("get(index): " + linkedList.get(3));
System.out.println("getFirst: " +linkedList.getFirst());
System.out.println("getLast: " +linkedList.getLast());
}
}
输出:
注意到了,链表前后没有产生变化。
push、pop、poll
voidpush(E e):与addFirst一样,实际上它就是addFirst;
E pop():与removeFirst一样,实际上它就是removeFirst;
E poll():查询并移除第一个元素;
示例代码:
import java.util.*;public classtest{public static voidmain(String[] args) {
LinkedList linkedList = new LinkedList<>();
linkedList.push("first");
linkedList.push("second");
linkedList.push("second");
linkedList.push("third");
linkedList.push("four");
linkedList.push("five");
System.out.println(linkedList);
System.out.println("pop: " +linkedList.pop());
System.out.println("after pop: " +linkedList);
System.out.println("poll: " +linkedList.poll());
System.out.println("after poll: " +linkedList);
}
}
输出:
通过代码示例可以看出:push,pop的操作已经很接近stack的操作了。
如果链表为空的时候,看看poll与pop是啥区别:
import java.util.*;public classtest{public static voidmain(String[] args) {
LinkedList linkedList = new LinkedList<>();
System.out.println("pop: " +linkedList.poll());
System.out.println("poll: " +linkedList.pop());
}
}
输出
可以看出poll返回null,而pop则产生异常。
peek
E peek():获取第一个元素,但是不移除;
E peekFirst():获取第一个元素,但是不移除;
E peekLast():获取最后一个元素,但是不移除
示例代码
import java.util.*;public classtest{public static voidmain(String[] args) {
LinkedList linkedList = new LinkedList<>();
linkedList.push("first");
linkedList.push("second");
linkedList.push("second");
linkedList.push("third");
linkedList.push("four");
linkedList.push("five");
System.out.println("linkedList: " +linkedList);
System.out.println("peek: " +linkedList.peek());
System.out.println("peekFirst: " +linkedList.peekFirst());
System.out.println("peekLast: " +linkedList.peekLast());
System.out.println("linkedList: " +linkedList);
}
}
输出:
如果没找到对应的元素,统统输出null:
import java.util.*;public classtest{public static voidmain(String[] args) {
LinkedList linkedList = new LinkedList<>();
System.out.println("linkedList: " +linkedList);
System.out.println("peek: " +linkedList.peek());
System.out.println("peekFirst: " +linkedList.peekFirst());
System.out.println("peekLast: " +linkedList.peekLast());
}
}
输出:
offer
booleanoffer(E e):在链表尾部插入一个元素;booleanofferFirst(E e):与addFirst一样,实际上它就是addFirst;boolean offerLast(E e):与addLast一样,实际上它就是addLast;
示例代码
import java.util.*;public classtest{public static voidmain(String[] args) {
LinkedList linkedList = new LinkedList<>();
linkedList.push("first");
linkedList.push("second");
linkedList.push("second");
linkedList.push("third");
linkedList.push("four");
linkedList.push("five");
System.out.println("linkedList: " +linkedList);
linkedList.offer("six");
System.out.println("linkedList: " +linkedList);
linkedList.offerFirst("zero");
System.out.println("linkedList: " +linkedList);
linkedList.offerLast("seven");
System.out.println("linkedList: " +linkedList);
}
}
输出:
其他
booleancontains(Object o) 如果此列表包含指定的元素方法返回true。
E element() 此方法返回此列表的头部
E set(intindex,E element) 此方法替换在与指定元素在此列表中指定位置的元素。
subList(int index, int index) 方法是在给定的ArrayList集合中获取给定下标的子集合。注意范围是[)。
代码示例
import java.util.*;public classtest {public static voidmain(String[] args) {
LinkedList linkedList = new LinkedList<>();
linkedList.push("first");
linkedList.push("second");
linkedList.push("second");
linkedList.push("third");
linkedList.push("four");
linkedList.push("five");
System.out.println("linkedList: " +linkedList);
System.out.println("linkedList.contains(\"second\"): " + linkedList.contains("second"));
System.out.println("linkedList.contains(\"six\"): " + linkedList.contains("six"));
System.out.println("linkedList.element(): " +linkedList.element());
System.out.println("linkedList: " +linkedList);
System.out.println("linkedList.set(3, \"set\"): " + linkedList.set(3, "set"));
System.out.println("linkedList: " +linkedList);
System.out.println("linkedList.subList(2,4): " + linkedList.subList(2,4));
System.out.println("linkedList: " +linkedList);
}
}
(三)Vector
Vector 可实现自动增长的对象数组。
java.util.vector提供了向量类(Vector)以实现类似动态数组的功能。
创建了一个向量类的对象后,可以往其中随意插入不同类的对象,即不需顾及类型也不需预先选定向量的容量,并可以方便地进行查找。
对于预先不知或者不愿预先定义数组大小,并且需要频繁地进行查找,插入,删除工作的情况,可以考虑使用向量类。
向量类提供了三种构造方法:
publicvector()public vector(int initialcapacity,intcapacityIncrement)public vector(int initialcapacity)
使用第一种方法系统会自动对向量进行管理,若使用后两种方法,则系统将根据参数,initialcapacity设定向量对象的容量(即向量对象可存储数据的大小),当真正存放的数据个数超过容量时。系统会扩充向量对象存储容量。
参数capacityincrement给定了每次扩充的扩充值。当capacityincrement为0的时候,则每次扩充一倍,利用这个功能可以优化存储。
在Vector类中提供了各种方法方便用户的使用:
1.插入功能
(1)public final synchronized void adddElement(Object obj)
将obj插入向量的尾部。obj可以是任何类型的对象。对同一个向量对象,亦可以在其中插入不同类的对象。但插入的应是对象而不是数值,所以插入数值时要注意将数组转换成相应的对象。
例如:要插入有整数1时,不要直接调用addElement(1)。正确方法为
import java.util.*;public classtest {public static voidmain(String[] args) {
Vector v1 = new Vector();
Integer i= new Integer(1);
v1.addElement(i);
System.out.println(v1);
}
}
(2)public final synchronized void setElementAt(Object obj,int index)
将index处的对象设置成obj,原来的对象将被覆盖。
import java.util.*;public classtest {public static voidmain(String[] args) {
Vector v1 = new Vector();
v1.addElement("Frist");
v1.addElement("Second");
System.out.println(v1);
v1.setElementAt("我插!", 1);
System.out.println(v1);
}
}
输出:
(3)public final synchronized void insertElementAt(Object obj,int index)
在index指定的位置插入obj,原来对象以及此后的对象依次往后顺延。
import java.util.*;public classtest {public static voidmain(String[] args) {
Vector v1 = new Vector();
v1.addElement("Frist");
v1.addElement("Second");
System.out.println(v1);
v1.insertElementAt("我插!", 1);
System.out.println(v1);
}
}
输出:
2.删除功能
(1)public final synchronized void removeElement(Object obj)
从向量中删除obj,若有多个存在,则从向量头开始试,删除找到的第一个与obj相同的向量成员。
import java.util.*;public classtest {public static voidmain(String[] args) {
Vector v1 = new Vector();
v1.addElement("First");
v1.addElement("Second");
v1.addElement("Thrid");
v1.addElement("First");
System.out.println(v1);
v1.removeElement("First");
System.out.println(v1);
}
}
输出:
(2)public final synchronized void removeAllElements();
删除向量所有的对象
import java.util.*;public classtest {public static voidmain(String[] args) {
Vector v1 = new Vector();
v1.addElement("First");
v1.addElement("Second");
v1.addElement("Thrid");
v1.addElement("First");
System.out.println(v1);
v1.removeAllElements();
System.out.println(v1);
}
}
输出:
(3)public fianl synchronized void removeElementAt(int index)
删除index所指的地方的对象
import java.util.*;public classtest {public static voidmain(String[] args) {
Vector v1 = new Vector();
v1.addElement("First");
v1.addElement("Second");
v1.addElement("Thrid");
v1.addElement("First");
System.out.println(v1);
v1.removeElementAt(1);
System.out.println(v1);
}
}
输出:
3.查询搜索功能
(1)public final int indexOf(Object obj)
从向量头开始搜索obj,返回所遇到的第一个obj对应的下标,若不存在此obj,返回-1.
import java.util.*;public classtest {public static voidmain(String[] args) {
Vector v1 = new Vector();
System.out.println(v1.indexOf("First"));
v1.addElement("First");
v1.addElement("Second");
v1.addElement("Thrid");
v1.addElement("First");
System.out.println(v1);
System.out.println(v1.indexOf("First"));
}
}
输出:
(2)public final synchronized int indexOf(Object obj,int index)
从index所表示的下标处开始搜索obj.
import java.util.*;public classtest {public static voidmain(String[] args) {
Vector v1 = new Vector();
System.out.println(v1.indexOf("First",1));
v1.addElement("First");
v1.addElement("Second");
v1.addElement("Thrid");
v1.addElement("First");
System.out.println(v1);
System.out.println(v1.indexOf("First", 1));
}
}
输出:
(3)public final int lastIndexOf(Object obj)
从向量尾部开始逆向搜索obj.
import java.util.*;public classtest {public static voidmain(String[] args) {
Vector v1 = new Vector();
System.out.println(v1.lastIndexOf("First",1));
v1.addElement("First");
v1.addElement("Second");
v1.addElement("Thrid");
v1.addElement("First");
System.out.println(v1);
System.out.println(v1.lastIndexOf("First", 1));
}
}
输出:
(4)public final synchornized int lastIndex(Object obj,int index)
从index所表示的下标处由尾至头逆向搜索obj.
(5)public final synchornized firstElement()
获取向量对象中的首个obj
(6)public final synchornized Object lastElement()
获取向量对象的最后一个obj
4.其他功能
(1)public final int size();
此方法用于获取向量元素的个数。它们返回值是向量中实际存在的元素个数,而非向量容量。可以调用方法capacity()来获取容量值。
(2)public final synchronized void setSize(int newsize);
此方法用来定义向量的大小,若向量对象现有成员个数已经超过了newsize的值,则超过部分的多余元素会丢失。
程序中定义Enumeration类的一个对象Enumeration是java.util中的一个接口类,
(3)public final synchronized Enumeration elements();
此方法将向量对象对应到一个枚举类型。java.util包中的其他类中也都有这类方法,以便于用户获取对应的枚举类型。
在Enumeration中封装了有关枚举数据集合的方法。
方法 hasMoreElement() 来判断集合中是否还有其他元素。
方法 nextElement() 来获取下一个元素
以下代码就是用hasMoreElement()和 nextElement()遍历Vector
importjava.util.Enumeration;importjava.util.Iterator;importjava.util.List;importjava.util.Vector;public classtest {public voidtest01() {
Vector hs = new Vector();
hs.add("aa");
hs.add("bb");
hs.add("aa");
hs.add("cc");
hs.add("aa");
hs.add("dd");
printSet2(hs);
}public voidprintSet(List hs) {
Iterator iterator=hs.iterator();while(iterator.hasNext()) {
System.out.println(iterator.next());
}
}public void printSet2(Vectorhs) {
Enumeration elements =hs.elements();while(elements.hasMoreElements()) {
System.out.println(elements.nextElement());
}
}public static voidmain(String[] args) {newtest().test01();
}
}
PS:同时也有一个结论 Vector是有序的,可以重复的。
(四)ArrayList、LinkedList、Vector的底层实现和区别
List 有序, 可重复, 有索引。三者均为可伸缩数组。
ArrayList:底层数据结构是数组结构。 线程不安全的。 所以ArrayList的出现替代了Vector, 但是查询的速度很快。默认扩充为原来的1.5倍。
LinkedList:底层是链表数据结构。线程不安全的, 同时对元素的增删操作效率很高。但查询慢。
Vector:底层数据结构是数组结构。 jdk1.0版本。线程安全的。 无论增删还是查询都非常慢。默认扩充为原来的2倍。
Vector 和 ArrayList都是基于存储元素的Object[ ] array来实现的。
LinkedList是采用双向列表来实现的。
1、 线程同步,Vector线程安全,ArrayList线程不安全。
2、 效率问题,Vector效率低,ArrayList效率高。
3、 增长数量,Vector以1.5倍增长,ArrayList以2倍增长。
List集合子类Vector这个类已经不常用了, 我就说里面的一个方法, Elements方法, 这个方法的返回值是枚举接口, 里面有两个方法, 判断和获取。此接口Enumeration的功能与 Iterator 接口的功能是重复的。Enumeration的名称和方法的名称过程, 书写很麻烦。 所以被Iterator所取代。
ArrayList是实现了基于动态数组的数据结构,LinkedList基于双线链表的数据结构。
ArrayList可以随机定位对于新增和删除操作add和remove,LinedList比较占优势
具有Collection接口必备的iterator()方法外,List还提供一个listIterator()方法ListIterator多了一些add()之类的方法,允许添加,删除,设定元素,还能向前或向后遍历。
Vector与ArrayList唯一的区别是,Vector是线程安全的,即它的大部分方法都包含有关键字synchronized,因此,若对于单一线程的应用来说,最好使用ArrayList代替Vector,因为这样效率会快很多(类似的情况有StringBuffer线程安全的与StringBuilder线程不安全的);而在多线程程序中,为了保证数据的同步和一致性,可以使用Vector代替ArrayList实现同样的功能。