全部章节 >>>>
本章目录
7.1 集合概述7
7.1.1 Java集合体系概述
为了使程序方便地存储和操纵数目不固定的一组数据,JDK类库中提供了Java集合,所有Java集合类都位于java.util包中。与Java数组不同,Java集合不能存放基本数据类型,而只能存放对象。
Java集合类主要由两个接口派生而出,即Collection和Map接口。Collection和Map是Java集合框架的最上层的父接口,这两个接口又包含其他的子接口和实现类。
Java集合主要包括三种类型: Set(集),List(列表),Map(映射)。
Collection集合体系的继承树
实线表示继承关系,虚线表示实现关系
Map体系的继承树
Java集合的三种数据类型存储示意图
1、Set特点
类似于一个罐子,将一个对象添加到Set集合时,Set集合无法记住添加此元素的顺序
Set集合中的元素是不能重复的,否则系统无法准确识别此元素。
2、List特点
类似于一个数组,它可以记录每个元素添加的顺序,但List长度可变。
3、Map特点
Map集合的存放方式,同样类似于一个罐子,但Map集合中的每项数据都由两个值组成。它们分别为key和value,key不可以重复,但是value可以重复。
Collection接口常用方法
方法名 |
说明 |
boolean add(Object obj) |
向集合中添加一个元素 |
boolean addAll(Collection c) |
将集合c的所有元素添加到指定集合中 |
void clear() |
清除集合中的所有元素,此时集合长度变为0 |
boolean contains(Object obj) |
返回集合中是否包含指定的元素 |
boolean contains(Collection c) |
返回集合中是否包含指定的c集合 |
Boolean isEmpty() |
判断集合是否为空。集合长度为0时返回true,否则返回false |
Iterator iterator() |
返回一个Iterator对象,用于遍历集合中的元素 |
boolean remove(Object obj) |
删除集合中的指定元素obj,当集合中包含一个或多个元素obj时,仅删除第一个符合条件的元素 |
int size() |
返回集合中元素的个数 |
Object[] toArray() |
将当前集合转换成一个Object[]类型的数组 |
7.1.2 实践练习
7.2 List集合
List集合代表一个元素是有序的、且可以重复的、可以为null的集合。
集合中每个元素都有其对应的顺序索引,List集合允许添加重复元素,可以通过索引来访问指定位置的集合元素。
List 的数据结构就是一个序列,存储内容时直接在内存中开辟一块连续的空间,然后将空间地址与索引对应。
List最常见的实现类是ArrayList和LinkedList。
除Collection接口的所有方法之外List还拥有的其他方法
方法名 |
说明 |
void add(int index, Object element) |
添加对象element到位置index上 |
boolean addAll(int index, Collection collection) |
在index位置后添加容器collection中所有的元素 |
Object get(int index) |
取出下标为index的位置的元素 |
int indexOf(Object element) |
查找对象element在List中第一次出现的位置 |
int lastIndexOf(Object element) |
查找对象element在List中最后出现的位置 |
Object remove(int index) |
删除index位置上的元素,并返回被删除的这个元素 |
Object set(int index,Object element) |
将index位置上的所示对象替换为element并返回被替换 |
7.2.1 ArrayList实现类
ArrayList是基于数组实现的List类,ArrayList底层是通过一个长度可变的数组实现的。
ArrayList允许对元素进行快速的随机访问,但是向ArrayList中插入与删除元素的速度较慢。
示例: 演示ArrayList类使用方法
-
//创建ArrayList对象
-
ArrayList arrayList=
new ArrayList();
-
arrayList.add(
"JAVA-DEMO");
//向集合中添加字符串对象
-
arrayList.add(
new Hero());
//向集合中添加用户自定义对象
-
System.out.println(
"arrayList集合的大小="+arrayList.size());
-
for(
int i=
0;i<arrayList.size();i++)
//遍历集合元素
-
Object obj=arrayList.get(i);
//按照下标获取元素
-
boolean flag=arrayList.contains(
"JAVA-DEMO");
//是否包含字符串"JAVA-DEMO"
-
Object obj=arrayList.remove(
"JAVA-DEMO");
//删除指定元素字符串"JAVA-DEMO"
-
System.out.println(
"被删除的元素="+obj);
-
arrayList.set(
0,
"ANDROID");
//将集合下标为0的元素修改为ANDORID
7.2.2 LinkedList实现类
LinkedList类在实现时,采用链表数据结构,所以向LinkedList中插入和删除元素的速度较快,随机访问速度则相对较慢(随机访问是获取指定下标位置的元素)
LinkedList单独具有addFirst()、addLast()、getFirst()、getLast()、removeFirst()和removeLast()方法。这些方法使LinkedList可以作为堆栈、队列和双向队列来使用。
LinkedList常用方法
方法名 |
说明 |
void addFirst(Object o) |
将指定元素o插入列表起始位置 |
addLast(Object o) |
将指定元素o添加至列表末尾处 |
Object removeFirst() |
移除并返回列表的首元素 |
Object removeLast() |
移除并返回列表的首末元素 |
示例:演示LinkedList类使用方法
-
LinkedList linkedList=
new LinkedList();
-
ArrayList ayList=
new ArrayList();
-
ayList.add(
"JAVA-DEMO");
-
ayList.add(
'中');
-
//将ayList对象添加至linkedList集合中
-
linkedList.add(ayList);
-
//添加自定义类型对象
-
linkedList.add(
new Hero());
-
linkedList.addFirst(
99.8);
//向集合头部添加一个元素
-
Object obj=linkedList.removeFirst();
//删除头部元素
示例:比较ArrayList与LinkedList删除元素的效率
-
ArrayList aList=
new ArrayList();
//创建ArrayList集合
-
System.out.println(
"==========ArrayList==========");
-
long bTime=System.currentTimeMillis();
//获取当前系统的时间(毫秒数表示)
-
System.out.println(
"起始时间:"+bTime);
-
for(
int i=
0;i<
100000;i++)
-
aList.add(
"DEMO"+i);
//向集合中添加数据
-
int size=aList.size();
-
for(
int i=
0;i<size;i++)
-
aList.remove(
0);
//每次都删除集合中的第一个元素
-
long eTime=System.currentTimeMillis();
-
System.out.println(
"结束时间:"+eTime);
-
System.out.println(
"ArrayList添加、删除所用时间="+(eTime-bTime)+
"毫秒");
-
//创建LinkedList集合
-
LinkedList lList=
new LinkedList();
-
...
-
System.out.println(
"LinkedList添加、删除所用时间="+(edTime-bginTime)+
"毫秒");
示例:比较ArrayList与LinkedList访问元素的效率
-
ArrayList aList=
new ArrayList();
//创建ArrayList集合
-
System.out.println(
"==========ArrayList==========");
-
for(
int i=
0;i<
100000;i++)
-
aList.add(
"DEMO"+i);
//向集合中添加数据
-
//获取当前系统的时间(毫秒数表示)
-
long bTime=System.currentTimeMillis();
-
System.out.println(
"开始时间:"+bTime);
-
for(
int i=
0;i<
1000000000;i++)
-
aList.get(
99999);
//每次读取列表末尾元素
-
long eTime=System.currentTimeMillis();
-
System.out.println(
"结束时间:"+eTime);
-
System.out.println(
"ArrayList随机访问所用时间="+(eTime-bTime)+
"毫秒");
-
LinkedList lList=
new LinkedList();
//创建LinkedList集合
-
System.out.println(
"==========LinkedList==========");
-
...
-
for(
int i=
0;i<
1000000000;i++)
-
lList.get(
99999);
//每次读取列表末尾元素
-
...
-
System.out.println(
"LinkedList随机访问所用时间="+(edTime-bgTime)+
"毫秒");
-
经验:
List就是一个线性表接口,而ArrayList、LinkedList又是线性表的两种典型实现,ArrayList 是基于数组的线性表,而LinkedList是基于链表的线性表。
当对集合元素进行频繁的添加或删除操作时,使用LinkedList效率比较高,因为链表的插入和删除操作效率比较高。
当对集合元素进行频繁的读取操作时,使用ArrayList效率比较高,因为基于数组的线性表的随机访问效率比较高。
7.2.3 实践练习(一)
7.2.4 实践练习(二)
7.3 Set集合和Iterator迭代器
7.3.1 Set集合
Set集合,类似于一个瓶子,“装进”Set集合中的多个对象之间没有明显的顺序。
Set集合不允许包含相同的元素,如果试图将两个相同的元素加入同一个Set集合中,则添加操作失败返回false,且新元素不会被加入其集合中。
HashSet是Set接口的最常用的实现类。HashSet按Hash算法实现存储集合中的元素,因为其具有良好的存储和查找性能。
Set的排列顺序可能与添加顺序不同,Set元素值可以是null。
示例:添加Cat对象到HashSet集合
-
public
class Cat {
-
private String name;
-
private String color;
-
…
-
public String toString(){
//重新toString()
-
return
"名字:"+
this.name+
"-"+
"毛色:"+
this.color;
-
}
-
}
-
public
class HashSetTest {
-
public static void useHashSet(){
-
HashSet hs=
new HashSet();
-
hs.add(
"JAVA");
-
hs.add(
new Cat(
"加菲",
"黄色"));
-
hs.add(
new Cat(
"汤姆",
"青色"));
-
hs.add(
new Cat(
"加菲",
"黄色"));
-
hs.add(
"JAVA");
//添加重复对象"JAVA"
-
hs.add(
100);
//添加重复对象"JAVA"
-
System.out.println(
"HashSet对象集合="+hs);
-
}
-
…..
提问:有两条猫的名字和颜色一摸一样,怎么它们可以一起添加到Set集合?
分析:
这两条猫的名字和颜色一摸一样,但它们equals()返回值为false,hashCode()值也不相等。所以这两条猫不相同。
如果两条猫相同的逻辑是它们名字和颜色相同,则可通过重写Cat类的equals() 和hashCode() 。
示例:重写Cat的equals() 和hashCode()
-
public boolean equals(Object obj){
-
if(obj==
this){
-
return
true;
-
}
else{
-
if(obj
instanceof Cat){
-
Cat cat=(Cat)obj;
-
if(
this.name.equals(cat.name) &&
this.color.equals(cat.color))
-
return
true;
-
else
-
return
false;
-
}
else
-
return
false;
-
}
-
}
-
//重写hashCode()方法
-
public int hashCode(){
-
return
this.name.hashCode()*
this.color.hashCode();
-
}
-
-
重写hashCode()方法的一般规则如下:
在程序运行时,同一个对象的hashCode()方法应该返回相同的值。
当两个对象通过equals()方法比较返回true时,这两个对象的hashCode()方法应返回相等的值。
象中用作equals()方法比较标准的属性,都应该用于计算hashCode的值。
7.3.2 Iterator迭代器
Iterator接口隐藏了各种Collection实现类的底层细节,该接口提供了遍历Collection集合元素的统一编程接口。
迭代器是一种设计模式,它是一个对象,它可以遍历并选择序列中的对象,而开发人员不需要了解该序列的底层结构。迭代器通常被称为“轻量级”对象,因为创建它的代价小。
由于Set集合中存储的是无序的元素,因此无法在循环中按照下标获取Set集合中的元素,所以利用Iterator接口遍历Set集合中的元素尤为方便。
Iterator常用方法
方法名 |
说明 |
boolean hasNext(Object o) |
如果被迭代的集合中的元素没有遍历完成,则返回true |
Object next() |
返回集合中的下一个元素 |
Void remove() |
将迭代器新返回的元素删除 |
示例:Iterator迭代器应用案例
-
HashSet hs=
new HashSet();
-
hs.add(
1);
-
hs.add(
new Date());
-
hs.add(
"ANDORID");
-
hs.add(
new Cat(
"加菲",
"粉色"));
-
//调用HashSet对象的iterator()方法,返回Iterator实例
-
Iterator it=hs.iterator();
-
//使用while循环,循环判断迭代器中是否还有元素
-
System.out.println(
"====使用迭代器遍历HashSet集合=====");
-
while(it.hasNext()){
-
//获取迭代器中的数据
-
Object obj=it.next();
-
System.out.println(obj);
-
}
7.3.3 实践练习
7.4 Map集合
Map用于保存具有映射关系的数据。Map集合中保存着两组值,一组值用于保存Map里的key,另外一组值保存Map的value。key和value可以为null。
key和value可以是任意类型的数据。Map的key不允许重复,即同一个Map对象的任何两个key通过equals()方法比较总是返回false。
key和value间存在单向一对一关系,即通过指定的key总能找到唯一的、确定的value。从Map中取出数据时,只要给出指定的key,就可以取出对应的value。
HashMap是Map接口最为常用的实现类,HashMap通过哈希码对其内部的映射关系进行快速查找。
7.4.1 Map集合
Map接口常用方法
方法名 |
说明 |
put(K key,V value) |
向映射中添加一对key与value的映射关系 |
Object get(Object key) |
返回映射中key所对应的value。如果该映射中不包含key,则返回null |
putAll(Map map) |
将映射map所有的键值映射关系添加到当前映射 |
containsKey(Object key) |
如果此映射包含指定键的映射关系,则返回true |
containsValue(Object value) |
如果此映射将一个或多个键映射到指定的value,则返回true |
keySet() |
将该集合中的所有键对象以Set集合的形式返回 |
values() |
将该集合中的所有值对象以Collection集合的形式返回 |
remove(Object key) |
如果存在指定的键key,则移除该键的映射关系,并返回与该键对象对应的值对象,否则返回null |
clear() |
从此映射中移除所有映射关系 |
isEmpty() |
如果此映射未包含键-值映射关系,则返回true |
size() |
返回此映射中的键-值映射关系的数量 |
示例:HashMap应用案例
-
Map hm=
new HashMap();
-
hm.put(
"JAVA",
"DEMO");
-
hm.put(
"中国",
"北京");
-
hm.put(
1,
"one");
-
hm.put(
true,
"正确" );
-
hm.put(
"中国",
"上海");
-
System.out.println(
"========HashMap集合添加元素后=======");
-
System.out.println(hm);
-
System.out.println(
"====按照Kye获取对应Value值====");
-
Object value=hm.get(
"中国");
-
System.out.println(
"key值为中国对应的value值="+value);
-
System.out.println(
"HashMap集合的大小="+hm.size());
-
System.out.println(
"===遍历HashMap集合===");
-
//返回存储HashMap集合中的所有的key(键)的Set集合
-
Set set=hm.keySet();
-
Iterator it=set.iterator();
//返回key集合的Iterator迭代器
-
while(it.hasNext()){
//遍历key
-
Object key=it.next();
//得到HashMap集合中的key值
-
Object val=hm.get(key);
//通过key得到对应的value值
-
System.out.println(
"键="+key+
"\t"+
"值="+val);
-
}
HashMap与Hashtable的区别
HashMap |
Hashtable |
允许出现空值、空键 |
不允许出现空值、空键 |
线程异步,效率较高 |
线程同步,效率较低 |
继承自AbstractMap |
继承自Dictionary |
7.4.2 实践练习
总结:
- 所有Java集合类都位于java.util包中。与Java数组不同,Java集合不能存放基本数据类型,而只能存放对象。
- Java集合类主要由两个接口派生而出,即Collection和Map接口。Collection和Map是Java集合框架的最上层的父接口,这两个接口又包含其他的子接口和实现类。
- List集合代表一个元素是有序的、且可以重复的、可以为null的集合。可以通过get(int index)取出下标为index的元素。
- List最常见的实现类是ArrayList和LinkedList。当对集合元素进行频繁的读取操作时,使用ArrayList效率比较高;当对集合元素进行频繁的添加或删除操作时,使用LinkedList效率比较高。
- Set集合不允许包含相同的元素,Set的排列顺序可能与添加顺序不同,Set元素值可以是null,HashSet是Set接口的最常用的实现类。可以通过重写类的equals()和hashCode()方法定义对象相等的逻辑。
- Iterator迭代器提供了遍历Collection集合元素的统一编程接口。
- Map用于保存具有映射关系的数据。Map集合中保存着两组值,一组值用于保存Map里的key,另外一组值保存Map的value。key和value可以为null。
- Map接口的put(K key,V value)用于向映射中添加一对key与value的映射关系,get(Object key)用于返回映射中key所对应的value。
转载:https://blog.csdn.net/weixin_44893902/article/details/106649705