------<a href="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! -------
6.1 集合概述
6.1.1 集合出现的原因
面向对象语言对事物的体现都是以对象的形式,所以为了方便对多个对象的操作,就对对象进行存储,集合就是存储对象最常用的一种方式。
6.1.2 集合和数组的不同
数组虽然也可以存储对象,但长度是固定的;集合长度是可变的。数组中可以存储基本数据类型,集合只能存储对象。
6.1.3 集合的概念
集合是用来存储对象的,集合的长度是可变的,集合的底层依赖于数组,集合可以存储不同类型的对象,集合有很多的方法,便于操作集合中的元素
JDK为我们提供了一套完整的容器类库,这些容器可以用于存储各种类型的对象,并且长度都是可变的,我们把这些类统称为集合类,它们都位于java.util包中。
集合类存放于java.util包中。
集合类存放的都是对象的引用,而非对象本身,出于表达上的便利,我们称集合中的对象就是指集合中对象的引用(reference)。
集合类型主要有3种:set(集)、list(列表)和map(映射)。
6.1.3.1 集
集(set)是最简单的一种集合,它的对象不按特定方式排序,只是简单的把对象加入集合中,就像往口袋里放东西。对集中成员的访问和操作是通过集中对象的引用进行的,所以集中不能有重复对象。集也有多种变体,可以实现排序等功能,如TreeSet,它把对象添加到集中的操作将变为按照某种比较规则将其插入到有序的对象序列中。它实现的是SortedSet接口,也就是加入了对象比较的方法。通过对集中的对象迭代,我们可以得到一个升序的对象集合。
6.1.3.2 列表
列表的主要特征是其对象以线性方式存储,没有特定顺序,只有一个开头和一个结尾,当然,它与根本没有顺序的集是不同的。
列表在数据结构中分别表现为:数组和向量、链表、堆栈、队列。
6.1.3.3 映射
映射与集或列表有明显区别,映射中每个项都是成对的。映射中存储的每个对象都有一个相关的关键字(Key)对象,关键字决定了对象在映射中的存储位置,检索对象时必须提供相应的关键字,就像在字典中查单词一样。关键字应该是唯一的。
关键字本身并不能决定对象的存储位置,它需要对过一种散列(hashing)技术来处理,产生一个被称作散列码(hash code)的整数值,
散列码通常用作一个偏置量,该偏置量是相对于分配给映射的内存区域起始位置的,由此确定关键字/对象对的存储位置。理想情况下,散列处理应该产生给定范围内均匀分布的值,而且每个关键字应得到不同的散列码。
6.1.4 集合的特点
1,用于存储对象的容器。
2,集合的长度是可变的。
3,集合中不可以存储基本数据类型值(存的是对象)。
6.1.5 集合的分类
整个集合类按照存储的结构被分为单列集合和双列集合,单列集合的根接口是Collection,双列集合的根接口是Map集合。在Collection接口中主要有两个子接口,分别是List和Set。List集合的特点是元素有序、包含重复元素,Set集合的特点是元素无序、不包含重复元素。Map集合中存储的是键值映射关系,元素都是成对出现的,就像上学时的同桌一样。Map接口的主要子接口有HashMap和TreeMap。
6.1.6 几个思考考题
思考一:数组能否储存对象?
答: 可以,如:
Person [] p = new Person[10];
Person [0] = new Person(” ”, ” ” );
但是这样做是有弊端的:初始化长度固定。
集合不用固定初始化长度,但是集合不能存储基本数据类型的数据,集合的底层其实就是用数组,所以集合的运行速度慢于数组。所以:
如果存储元素是对象,且长度可变,尽量选集合。
如果储存元素是基本数据类型,且长度固定,尽量选择数组。
思考二:集合能否直接打印?
答: 可以,collection 类重写了toString()方法。
6.1.7 常见的集合遍历方式(单列)
6.1.7.1 方式一:for
从0循环到集合的size()-1, 每次获取其中一个
6.1.7.2 方式二:foreach
for (类型 变量名 : 容器) { 循环体 } 容器中有多少个元素就执行多少次循环体, 每次循环变量指向容器中不同的元素,底层实际还是迭代器。
6.1.7.3 方式三:迭代器
调用iterator()方法获取迭代器, 使用hasNext()判断是否包含下一个元素, 使用next()获取下一个元素
有两种方法实现,一种是用while,一种是用for,建议用for迭代,省内存(省的不多)。
6.1.7.4 vector中的Enumeration
枚举进行迭代(特有)
注意: 迭代时删除的问题
1. for循环:
删除时由于后面的元素会向前移动, 所以删除之后循环变量要--
2. 迭代器:
要删除元素时必须使用Iterator中的remove()否则会抛出异常
3. 增强for循环:
不能删除
6.3 Collection接口
6.3.1 Collection接口概述
框架的顶层Collection接口,常见的子类接口有:
List:有序(存入和取出的顺序一致),元素都有索引(角标),元素可以重复。
Set:元素不能重复,无序。
6.3.2 Collection接口常见方法
1,添加。
boolean add(Object obj):
boolean addAll(Collection coll):
2,删除。
boolean remove(object obj):
boolean removeAll(Collection coll);
void clear();
3,判断:
boolean contains(object obj):
boolean containsAll(Colllection coll);
boolean isEmpty():判断集合中是否有元素。
4,获取:
int size():
Iterator iterator():
取出元素的方式:迭代器。
该对象必须依赖于具体容器,因为每一个容器的数据结构都不同。
所以该迭代器对象是在容器中进行内部实现的。
对于使用容器者而言,具体的实现不重要,只要通过容器获取到该实现的迭代器的对象即可,
也就是iterator方法。
Iterator接口就是对所有的Collection容器进行元素取出的公共接口。
其实就是抓娃娃游戏机中的夹子!
5,其他:
boolean retainAll(Collection coll);取交集。
Object[] toArray():将集合转成数组。
6.4 List接口
是可以完成对元素的增删改查。
有序、可重复、有索引。
List
|--Vector:内部是数组数据结构,是同步的。增删,查询都很慢!
|--ArrayList:内部是数组数据结构,是不同步的。替代了Vector。查询的速度快。
|--LinkedList:内部是链表数据结构,是不同步的。增删元素的速度很快。
6.4.1 ArrayList
6.4.1.1 概述
底层数据结构是数组结构。线程不安全的。所以ArrayList的出现替代了Vector.但是查询的速度很快。
ArrayList内部封装了一个默认长度为10的数组。当超出长度时,集合内部会自动生成一个新的数组。 将原数组中的元素复制到新数组中,在将新元素添加到新数组。
6.4.1.2 常用方法
1 添加
1.1 boolean add(Object)
在集合的尾部追加
1.2 void add(int, Object)
在指定的索引处,插入传进来的元素,其他的元素顺延
2 删除
2.1 E remove(int)
删除指定角标位置对应的元素
2.2 boolean remove(Object o)
删除和传入对象一样的元素
3 修改
E set(int, Object)
在指定的角标位置修改对应的元素
4 查找
4.1 E get(int)
根据指定角标位置获取对应的元素
4.2 int size()
元素的个数
5 判断
5.1 boolean isEmpty();
判断集合是否为空
5.2 boolean contains(Object);
判断集合是否包含传入的元素
6 清空
void clear();
清空集合size为零
6.4.1.3 其他方法(all)
1. boolean addAll(collection对象)
向原集合中添加传入的集合
2. boolean containsAll(collection对象)
判断原集合中是否包含传入的集合
3. boolean removeAll(collection对象)
删除原集合中和传入集合匹配的元素
4. boolean retainAll(collection对象)
取交集,原集合改变返回true,原集合存储的是交集,原集合不改变返回为假
6.4.2 LinkedList
6.4.2.1 LinkedList概述
内部是链表数据结构,是不同步的。增删元素的速度很快。
6.4.2.2 LinkedList特有方法
1. 添加
addFirst();
addLast():
jdk1.6
offerFirst();
offetLast();
2. 获取
getFirst();.//获取但不移除,如果链表为空,抛出NoSuchElementException.
getLast();
jdk1.6
peekFirst();//获取但不移除,如果链表为空,返回null.
peekLast():
3. 移除
removeFirst();//获取并移除,如果链表为空,抛出NoSuchElementException.
removeLast();
jdk1.6
pollFirst();//获取并移除,如果链表为空,返回null.
pollLast();
6.5 Set接口
6.5.1 Set概述
Set接口是单列集合的实现类,存放的是无序,不可重复的元素。对添加的元素有自己的判定标准,经过判定为不同的元素才可添加进该集合。所以Set集合一般在不想存放重复元素的时候使用。
6.5.2 HashSet
它是Set常见的实现类,添加元素时采用hash算法,通过hashCode()方法来确定元素的地址值。
它是通过hashCode()方法和equals()方法来确定元素是否重复的,因此为保证元素不重复,所添加的对象的类中必须要重写这两个方法。
6.5.3 ThreeSet
是Set中的常见实现类之一,其底层数据结构为二叉树结构,添加对象时会对元素进行自然排序。
而他对添加该集合的元素是否相同的判断标准有两种:
(1)让要排序的对象的类实现Comparable接口,重写其compartTo()方法,让该类的实例对象本身具备比较的功能。
(2)在对集合声明时在参数列表中传入一个自定义的比较器,集合根据比较器来对元素进行是否相同的判断,具体步骤是先实现Comparator接口,重写里面的compare(Object obj1,Object obj2)方法;
由于此种方式较为麻烦现在一般是用匿名内部类的形式直接写在集合声明代码行中。
6.6 Map 接口
6.6.1 Map概述
它是用于存储具有映射关系的键值对,是双列集合,它的键和值可以是任意的数据类型,但是键是唯一的,不能重复,而值可以重复。
6.6.2 HashMap
HashMap是Map实现类之一,类似于HashSet,也是通过Hash算法分配元素地址,并且查找也根据hashCode值。另外对添加元素的判断也是重写hashCode()方法和equals()方法,这两个方法分别对key值进行判断,若是hashCode值相同且,equals返回真才判别元素相同。
6.6.3 TreeMap
TreeMap和TreeSet类似,采用二叉树数据结构来存储元素,对添加进的键值进行自然排序,他也和TreeSet一样有两种排序方式,可选择实现Comparable接口让添加元素具备比较性,也可实现Comparator接口自定义一个比较器来比较。
6.6.4 Map元素的遍历
对于HashMap和TreeMap,则有两种常用的遍历方式:
(1)通过keySet()方法返回由键组成的集合,迭代该集合的元素就拿到了所有的键,再调用get方法根据键拿到值;
(2)通过entrySet方法返回键值映射关系组成的集合,迭代该集合就拿到了一个个的键值映射关系,通过getKey方法拿到键,通过getValue方法拿到值。