1.为什么要用集合类
Java编程思想中指出:
通常,程序总是根据运行时才知道的某些条件去创建新对象。
在此之前,不会知道所需对象的数量,甚至不知道确切的类型。
为解决这个普遍的编程问题,需要在任意时刻和任意位置创建任意数量的对象。
所以,就不能依靠创建命名的引用来持有每一个对象:
MyType aReference;
因为你不知道实际上会需要多少这样的引用。
大多数语言都提供某种方法来解决这个基本问题。Java有多种方式保存对象(应该说是对象的引用)。例如前面曾经学习过的数组,它是编译器支持的类型。数组是保存一组对象的最有效的方式,如果你想保存一组基本类型数据,也推荐使用这种方式。但是数组具有固定的尺寸, 而在更一般的情况中,你在写程序时并不知道将需要多少个对象,或者是否需要更复杂的方式来存储对象,因此数组尺寸固定这一限制显得过于受限了。
Java实用类库还提供了一套相当完整的容器类来解决这个问题。
其中基本的类型是List、Set、Queue和Map。这些对象类型也称为集合类,但由于Java的类库中使用了Collection这个名字来指代该类库的一个特殊子集,所以我使用了范围更广的术语“容器”称呼它们。
解读:
-
Java保存对象的方式有:
-
数组【可以保存基本类型数据;数组尺寸固定;只能存储同一种类型的对象】
-
集合类【不可以保存基本类型数据;在根本上都是数组,只是可以动态改变数组的大小;结合泛型可以存储多种类型的对象】
-
-
Java中的容器指Collection、Map的统称
-
容器中存储的是对象的引用不是对象的值;数组在存储基本数据类型时是存储的对象的值
-
为什么使用集合? 可以封装一组对象的操作,降低编程难度,增加代码复用性,提高程序运行速度与质量。
2.集合中的概念
Java容器类类库的用途是“保存对象”,并将其划分为两个不同的概念:
- Collection。一个独立元素的序列,这些元素都服从一条或多条规则。List必须按照插入的顺序保存元素,而Set不能有重复元素。Queue按照排队规则来确定对象产生的顺序(通常与它们被插入的顺序相同)。
- Map。一组成对的“键值对”对象,允许你使用键来査找值。ArrayList允许你使用数字 来査找值,因此在某种意义上讲,它将数字与对象关联在了一起。映射表允许我们使用另一个 对象来査找某个对象,它也被称为“关联数组”,因为它将某些对象与另外一些对象关联在了一 起,或者被称为“字典”,因为你可以使用键对象来査找值对象,就像在字典中使用单词来定义 一样。Map是强大的编程工具。
什么是集合框架?
集合框架是一个代表、操作集合的统一架构。所有的集合框架都包含以下几点:
-
接口:表示集合的抽象数据类型。接口允许我们操作集合时不必关注具体实现,从而达到“多态”。在面向对象编程语言中,接口通常用来形成规范。
-
实现类:集合接口的具体实现,是重用性很高的数据结构。
-
算法:用来根据需要对实体类中的对象进行计算,比如查找,排序。 同一种算法可以对不同的集合实现类进行计算,这是利用了“多态”。重用性很高。
3.集合的分类

Collection接口及其常用实现

Map接口及其常用实现

附带Java集合最全结构展示图

4.常用集合类与对应数据结构
集合类是Java数据结构的实现。所以,从数据结构层面对比下集合类。
集合 | 接口/类 | 说明 |
---|---|---|
Collection | 接口 | 定义了集合的基本方法, |
List | 接口 | 元素有序,元素可重复。主要实现类:ArrayList,LinkedList,Vector。 |
Vector | 类 | 线性表的数组实现 |
Stack | 类 | 栈,Last in first out,继承自Vector |
ArrayList | 类 | 动态数组,源码底层维护着List的容量与实际长度 |
LinkedList | 类 | 双向链表,此外它还实现了Deque,即也实现了Queue |
Queue | 接口 | 队列,First in first out |
Deque | 接口 | 双向队列,Deque继承自Queue,并增加了首尾两端的进出队列操作 |
Map | 接口 | 一组元素结构为K、V型的集 |
HashMap | 类 | 哈希数组+链表,通过哈希函数能够快速地找到元素,无冲突的情况下仅需访问一次 ;1.8后哈希数组+链表+红黑树 |
HashTable | 类 | HashTable与HashMap的区别是其线程安全,同时它不允许K、V为null |
TreeMap | 类 | Map的二叉平衡树实现,根据K的hashcode排序 |
ConcurrentHashMap | 类 | 线程安全的HashMap,HashTable的替代者 |
Set | 接口 | 元素无序,元素不重复。主要实现类:HashSet,TreeSet,LinkedHashSet。 |
HashSet | 类 | 内部使用HashMap实现,K对应E,V保存了一个Object |
TreeSet | 类 | 内部由TreeMap实现,K对应E,V保存了一个Object |
LinkedHashSet | 类 | 哈希表和链表的结合,且是一个双向链表;不重复且同时具有可预测的迭代顺序 |
5.容器操作使用
Collection增删改查与遍历
作为集合的一个根接口,定义了一组对象和它的子类可以实现的方法:

对集合的基础操作,比如 :
int size() 获取元素个数
boolean isEmpty() 是否个数为 0
boolean contains(Object element) 是否包含指定元素
boolean add(E element) 添加元素,成功时返回 true
boolean remove(Object element) 删除元素,成功时返回 true
Iterator<E> iterator() 获取迭代器
还有一些操作整个集合的方法,比如 :
boolean containsAll(Collection<?> c) 是否包含指定集合 c 的全部元素
boolean addAll(Collection<? extends E> c) 添加集合 c 中所有的元素到本集合中,如果集合有改变就返回 true
boolean removeAll(Collection<?> c) 删除本集合中和 c 集合中一致的元素,如果集合有改变就返回 true
boolean retainAll(Collection<?> c) 保留本集合中 c 集合中两者共有的,如果集合有改变就返回 true
void clear() 删除所有元素
还有对数组操作的方法:
Object[] toArray() 返回一个包含集合中所有元素的数组
<T> T[] toArray(T[] a) 返回一个包含集合中所有元素的数组,运行时根据集合元素的类型指定数组的类型
在 JDK 8 以后,Collection 接口还提供了从集合获取连续的或者并行流:
Stream<E> stream()
Stream<E> parallelStream()
List接口与Set接口实现Collection接口常用的方法有:
List接口
List接口下的集合元素存储有序,可以重复。
List的特有功能
A:添加功能
void add(int index, Object obj):在指定位置添加元素
B:删除功能
Object remove(int index):根据指定索引删除元素,并把删除的元素返回。
C:修改功能
Object set(int index, Object obj):把指定索引位置的元素修改为指定的值,返回修改前的值。
D:获取功能
int indexOf(Object o):返回指定元素在集合中第一次出现的索引
Object get(int index):获取指定位置的元素
ListIterator listIterator():列表迭代器
E:截取功能
List subList(int fromIndex, int toIndex):截取集合。
Set 接口
Set接口下的元素无序,不可以重复。其下面常用有HashSet和TreeSet。
HashSet
底层数据结构是哈希表,线程不安全,效率高。
保证唯一性依赖两个方法:hashCode()和equals()。
顺序:
判断hashCode()值是否相同。
相同:继续走equals(),看返回值
如果true:就不添加到集合。
如果false:就添加到集合。
不同:就添加到集合。
TreeSet
底层数据结构是二叉树,线程不安全,效率高。
保证元素唯一性的方法时根据返回值是否是0。
保证排序的两种方式:
自然排序(元素具备比较性):实现Comparable接口
比较器排序(集合具备比较性):实现Comparator接口
遍历 Collection 的几种方式:
for-each语法
Collection<Person> persons = new ArrayList<Person>();
for (Person person : persons) {
System.out.println(person.name);
}
使用 Iterator 迭代器
Collection<Person> persons = new ArrayList<Person>();
Iterator iterator = persons.iterator();
while (iterator.hasNext) {
System.out.println(iterator.next);
}
使用 aggregate operations 聚合操作
Collection<Person> persons = new ArrayList<Person>();
persons
.stream()
.forEach(new Consumer<Person>() {
@Override
public void accept(Person person) {
System.out.println(person.name);
}
});
Map增删改查与遍历
map是一个键值对形式的集合。它的元素都是有键和值组成。Map的键(key)是唯一的,值(value)可以重复。
Map的功能:
A:添加功能
V put(K key ,V value) :当key在集合中不存在是,添加元素;当key存在时替换元素
B:判断功能
boolean containsKey (Object key) :判断指定的键是否在集合中存在
Boolean containsValue(Object value):判断指定的值是否在集合中存在
Boolean isEmpty() :判断集合是否为空
C:删除功能
Void clear():清除所有键值对数据
D:获取功能
Object get (Object key) :根据键获取值
Set<K> keyset(): 所有键的集合
Collection<V>values() :所有值的集合
E:长度功能
Int size()
Map常用的有HashMap、HashTable和TreeMap,遍历常用有3种方法:
Map<String, Object>map = new HashMap<String, Object>();
map.put(“test1”, object1);
……
map.put(“testn” , objectn);
(1).Map的values()方法可以获取Map值的集合:
Iterator it = map.values().iterator();
while(it.hasNext()){
Object obj = it.next();
}
(2).Map的keySet方法可以获取Map键的Set集合:
Set<String> keys = map.keySet();
for(Iterator it = key.iterator(); it.hasNext(); ){
String key = it.next();
Object obj = map.get(key);
}
(3).通过Map.entrySet使用iterator遍历key和value
Iterator<Map.Entry<Integer, String>> it = map.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<Integer, String> entry = it.next();
System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
}
(4).通过Map.entrySet遍历key和value,推荐,尤其是容量大时
for (Map.Entry<Integer, String> entry : map.entrySet()) {
//entry.getKey() ;entry.getValue();
System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
}
网友评论