集合

1.1 为什么要使用集合框架?

传统的容器(数组)进行增、删破坏性操作时,需要移动元素,可能导致性能问题同时添加、删除等算法和具体业务耦合在一起,增加了程序开发的复杂度。 

Java集合框架提供了一套性能优良、使用方便的接口和类,它们位于java.util包中

1.2 Collection

Collectionjava集合框架(collection-frame)的顶层接口。

Collection接口表示一个容器,容器中只能存储引用数据类型建议存同一类型的引用类型,方便后续遍历等操作。

容器中的元素可以是有序的可重复的,为List接口

也可能是无序的、唯一的称为Set接口。

 

 

1.2.1 集合常用方法

 

 1 public static void main(String[] args) {
 2 
 3  
 4 
 5 /**
 6 
 7  * 增:add/addAll
 8 
 9  * 删:clear/remove/removeAll/retainAll
10 
11  * 改:
12 
13  * 查:contains/containsAll/isEmpty/size
14 
15  */
16 
17  
18 
19 Collection c1 = new ArrayList();
20 
21  
22 
23 // 追加
24 
25 c1.add("apple"); // Object object = new String("apple");
26 
27 // c1.add(1);  // Object object = new Integer(1);
28 
29 c1.add("banana");
30 
31 System.out.println(c1);
32 
33  
34 
35 // 追加一个集合
36 
37 Collection c2 = new ArrayList();
38 
39 c2.add("java");
40 
41 c2.add("c++");
42 
43 c1.addAll(c2);
44 
45 System.out.println(c1);
46 
47  
48 
49 // clear
50 
51 //c1.clear();
52 
53  
54 
55 // c1.remove("apple");
56 
57 // c1.removeAll(c2);
58 
59 //c1.retainAll(c2);
60 
61 //System.out.println(c1);
62 
63  
64 
65 System.out.println(c1.contains("apple"));
66 
67 c2.add("js");
68 
69 System.out.println(c1.containsAll(c2));
70 
71 // c1.clear();
72 
73 System.out.println(c1.isEmpty());
74 
75 // 返回集合元素的个数
76 
77 System.out.println(c1.size());
78 
79  
80 
81 System.out.println(c1.equals(c2));
82 
83  
84 
85 }

 

 

 

1.2.2 集合的遍历 

Iterable 可遍历的接口,集合接口继承于它,集合支持快速遍历。

 

 1 // 快速遍历
 2 
 3 // for-each
 4 
 5 // Object 表示元素类型
 6 
 7 // item表示迭代变量
 8 
 9 // c1表示集合
10 
11 for (Object item : c1) {
12 
13 System.out.println(item.toString());
14 
15 }

 

快速遍历的本质

Collection继承Iterable接口,表示集合支持快速遍历。Iterable接口定义了一个方法iterator()用于获取集合的迭代器,是一个Iterator接口类型,iterator()内部返回一个实现类实现类Iterator接口这个实现类一定具有hasNextnext方法用于判断是否有下一个元素和获取下一个元素。快速遍历就是基于迭代器工作的。

 

 1 public static void main(String[] args) {
 2 
 3  
 4 
 5  
 6 
 7 Collection c1 = new ArrayList();
 8 
 9 c1.add("apple");
10 
11 c1.add("banana");
12 
13 c1.add("coco");
14 
15  
16 
17  
18 
19 // 快速遍历
20 
21 // for-each
22 
23 // Object 表示元素类型
24 
25 // item表示迭代变量
26 
27 // c1表示集合
28 
29 for (Object item : c1) {
30 
31 System.out.println(item.toString());
32 
33 }
34 
35  
36 
37 // 迭代器遍历(国内)
38 
39 Iterator it = c1.iterator();
40 
41 while(it.hasNext()) {
42 
43 Object item = it.next();
44 
45 System.out.println(item.toString());
46 
47 }
48 
49  
50 
51 // 国外
52 
53 for(Iterator it2=c1.iterator();it2.hasNext();) {
54 
55 Object item = it2.next();
56 
57 System.out.println(item.toString());
58 
59 }
60 
61 }

 

1.3 List接口

List 接口中的元素时有序的、可重复的。List接口的元素通过索引(index)确定元素的顺序。

有序的 collection(也称为序列)。可以对列表中每个元素的插入位置进行精确地控制。用户可以根据元素的整数索引(在列表中的位置)访问元素,并搜索列表中的元素 

1.3.1 List常用方法

 1 public static void main(String[] args) {
 2 
 3  
 4 
 5 /**
 6 
 7  * 增:add/addAll/add(index,el)/addAll(index,collection)
 8 
 9  * 删:clear/remove/removeAll/remove(index)
10 
11  * 改:set(index,el)
12 
13  * 查:get(index)/indexOf/lastIndexOf()
14 
15  * 其他:contains/containsAll/isEmpty/size
16 
17  */
18 
19 List list1 = new ArrayList();
20 
21 // 添加元素
22 
23 list1.add("apple");
24 
25 list1.add("banana");
26 
27 // 在指定位置添加元素
28 
29 list1.add(0, "coco");
30 
31  
32 
33 System.out.println(list1);
34 
35  
36 
37 List list2 = new ArrayList();
38 
39 list2.add("java");
40 
41 list2.add("c++");
42 
43  
44 
45 list1.addAll(1, list2);
46 
47 System.out.println(list1);
48 
49  
50 
51 // 删除
52 
53 list1.remove(0);
54 
55 System.out.println(list1);
56 
57  
58 
59 // 修改
60 
61 list1.set(0, "javax");
62 
63 System.out.println(list1);
64 
65  
66 
67 //
68 
69 System.out.println(list1.get(0));
70 
71 list1.add("apple");
72 
73 list1.add("apple");
74 
75 System.out.println(list1);
76 
77 System.out.println(list1.indexOf("apple"));
78 
79 System.out.println(list1.lastIndexOf("apple"));
80 
81 }

 

1.3.2 List接口遍历 

ListIterator 继承Iterator,在Iterator基础上提供了以正向遍历集合,也可以以逆序遍历集合。

hasNext/next 以正向遍历

hasPrevious/previous 以逆序遍历

 

 1 public static void main(String[] args) {
 2 
 3  
 4 
 5  
 6 
 7 List list1 = new ArrayList();
 8 
 9 list1.add("apple");
10 
11 list1.add("banana");
12 
13 list1.add("coco");
14 
15  
16 
17 // 【1】快速遍历
18 
19 System.out.println("--for each--");
20 
21 for (Object item : list1) {
22 
23 System.out.println(item.toString());
24 
25 }
26 
27  
28 
29 // 【2】普通for
30 
31 System.out.println("--for--");
32 
33 for(int i=0;i<list1.size();i++) {
34 
35 System.out.println(list1.get(i));
36 
37 }
38 
39  
40 
41 // 【3】集合迭代器
42 
43 System.out.println("--iterator--");
44 
45 Iterator it = list1.iterator();
46 
47 while(it.hasNext()) {
48 
49 System.out.println(it.next());
50 
51 }
52 
53  
54 
55 System.out.println("--list iterator--");
56 
57 // 正向遍历
58 
59 ListIterator it2 = list1.listIterator();
60 
61 while(it2.hasNext()) {
62 
63 System.out.println(it2.next());
64 
65 }
66 
67  
68 
69 // 逆序遍历
70 
71 while(it2.hasPrevious()) {
72 
73 System.out.println(it2.previous());
74 
75 }
76 
77  
78 
79 System.out.println("--list iterator with index--");
80 
81 ListIterator it3 = list1.listIterator(1);
82 
83 while(it3.hasNext()) {
84 
85 System.out.println(it3.next());
86 
87 }
88 
89 }

 

1.4 数据结构(补充) 

数据结构就是数据在内存中存储结构。根据存储的方式不同,分为线性表、二叉树、图、栈、队列等

1.4.1 线性

线性表数据按照一定的逻辑顺序存储在内存中。线性表是有序的。线性表根据内存的物理结构分为两种:数组和链表

数组是一种逻辑上有序的线性表,物理上也连续

 

链表是一种逻辑上有序的线性表,但物理上不连续。

数组和链表的区别 

相同点:逻辑上有序的线性表

 

不同点:

数组在查询时效率高,在添加、删除元素时效率低(涉及移动元素)

链表在查询时效率(每次从头开始不能跳跃访问),在添加、删除元素时效率高(不涉及移动元素)

1.4.2 

特性:进后出,后进先出

 

1.4.3 队列 

特性:进先出

 

  

1.5 ArrayList/Vector

ArrayList List接口的实现类,底层数据结构是数组实现大小可变的数组。

ArrayList 线程不安全,jdk1.2

ArrayList 底层数据结构是数组,默认数组大小是10,如果添加的元素个数超过默认容量,ArrayList会自动拓容,拓容原则:newCapacity = oldCapacity + oldCapacity / 2;

如果未来确定序列的元素不在增加,通过调用trimToSize()调制容量至合适的空间。

ArrayList作为List接口的实现类,常用方法和遍历方法参考List接口。

Vector 是List的实现类,底层数据结构也是数组,也是大小可变的数组

Vector是线程安全的,jdk1.0

Vector底层数据结构是数组,默认数组大小是10,如果添加的元素个数超过默认容量,Vector会自动拓容,拓容原则:newCapacity = oldCapacity +capacityIncrement(增长因子);如果未来确定序列的元素不在增加,通过调用trimToSize()调制容量至合适的空间。

注意:Vector 实现List接口的同时,同添加了自身特有的方法xxxElement,未来使用时为了程序的可拓展性,一定要按照接口来操作Vector

1.6 LinkedList

LinkedListList接口的实现类,底层数据结构是链表。

LinekList常用方法和遍历方法参照List接口

LinkedList 线程不安全

了实现List接口, 实现栈接口

push入栈操作 / pop出栈操作

 1 public class Test01 {
 2 
 3 public static void main(String[] args) {
 4 
 5 LinkedList list = new LinkedList();
 6 
 7 list.push("apple");
 8 
 9 list.push("banana");
10 
11 list.push("coco");
12 
13  
14 
15  
16 
17 System.out.println(list.pop());
18 
19 System.out.println(list.pop());
20 
21 System.out.println(list.pop());
22 
23  
24 
25 // java.util.NoSuchElementException
26 
27 System.out.println(list.pop());
28 
29 }
30 
31 }

队列(Queue)接口

 

add/remove/element() 可能会出现NoSuchElementException异常 

 1 public static void main(String[] args) {
 2 
 3  
 4 
 5 LinkedList queue = new LinkedList();
 6 
 7 // 入队
 8 
 9 /**
10 
11  * 队列头                   队列尾
12 
13  *<-----          <-----
14 
15  * [apple, banana, coco]
16 
17  */
18 
19 queue.add("apple");
20 
21 queue.add("banana");
22 
23 queue.add("coco");
24 
25 System.out.println(queue);
26 
27  
28 
29 // 出队
30 
31 System.out.println(queue.remove());
32 
33 System.out.println(queue.remove());
34 
35 System.out.println(queue.remove());
36 
37 System.out.println(queue);
38 
39  
40 
41 // java.util.NoSuchElementException
42 
43 System.out.println(queue.remove());
44 
45  
46 
47  
48 
49 // 获取表头元素
50 
51 System.out.println(queue.element());
52 
53 }

 

offer/poll/peek 可能会返回特殊值(null) 

 1 public static void main(String[] args) {
 2 
 3  
 4 
 5 LinkedList queue = new LinkedList();
 6 
 7 // 入队
 8 
 9 /**
10 
11  * 队列头                   队列尾
12 
13  *<-----          <-----
14 
15  * [apple, banana, coco]
16 
17  */
18 
19 queue.offer("apple");
20 
21 queue.offer("banana");
22 
23 queue.offer("coco");
24 
25  
26 
27 // 出队列
28 
29 //System.out.println(queue.poll());
30 
31 //System.out.println(queue.poll());
32 
33 //System.out.println(queue.poll());
34 
35 System.out.println(queue);
36 
37  
38 
39 //System.out.println(queue.poll());
40 
41  
42 
43 // 获取表头元素
44 
45 System.out.println(queue.peek());
46 
47  
48 
49 }

 

双向队列(Deque)接口

 1 /**
 2 
 3  * 以双向队列形式操作LinkedList
 4 
 5  */
 6 
 7 public class Test04 {
 8 
 9 public static void main(String[] args) {
10 
11  
12 
13 LinkedList queue = new LinkedList();
14 
15 // 入队
16 
17 /**
18 
19  *<-----          <-----
20 
21  * [apple, banana, coco]
22 
23  * ---->          ----->
24 
25  */
26 
27  
28 
29 queue.addFirst("apple");
30 
31 queue.addFirst("banana");
32 
33 queue.addFirst("coco");
34 
35 System.out.println(queue);
36 
37  
38 
39 System.out.println(queue.removeLast());
40 
41 System.out.println(queue.removeFirst());
42 
43 System.out.println(queue.removeFirst());
44 
45 System.out.println(queue);
46 
47  
48 
49 // 获取头元素
50 
51 System.out.println(queue.getFirst());
52 
53  
54 
55 }
56 
57 }  

1.7 IteratorListIterator

Iterator迭代过程中不允许向集合中添加元素

 

 1 public static void main(String[] args) {
 2 
 3 ArrayList list = new ArrayList();
 4 
 5 list.add("apple");
 6 
 7 list.add("banana");
 8 
 9 list.add("coco");
10 
11  
12 
13 Iterator it = list.iterator();
14 
15 while(it.hasNext()) {
16 
17 String item = (String) it.next();
18 
19 if(item.equals("banana")) {
20 
21 list.add("test");
22 
23 }
24 
25 }
26 
27  
28 
29 System.out.println(list);
30 
31 }

 当通过Iterator集合迭代器遍历集合过程中,不能再向集合汇总添加元素否则出现ConcurrentModificationException 并发修改异常。

ListIterator允许程序员按任一方向遍历列表、迭代期间修改列表,并获得迭代器在列表中的当前位置

 1 public class Test01 {
 2 
 3 public static void main(String[] args) {
 4 
 5 ArrayList list = new ArrayList();
 6 
 7 list.add("apple");
 8 
 9 list.add("banana");
10 
11 list.add("coco");
12 
13  
14 
15 ListIterator it = list.listIterator();
16 
17 while(it.hasNext()) {
18 
19 String item = (String) it.next();
20 
21 if(item.equals("banana")) {
22 
23 it.add("test");
24 
25 }
26 
27 }
28 
29  
30 
31 System.out.println(list);
32 
33 }
34 
35 }

 

 

 

posted @ 2019-05-05 23:46 曾经有一首歌 阅读(...) 评论(...) 编辑 收藏