day02
【
Collection
、泛型】
主要内容
Collection
集合
迭代器
增强
for
第⼀章
Collection
集合
1.1
集合概述
在前⾯基础班我们已经学习过并使⽤过集合
ArrayList ,
那么集合到底是什么呢
?
集合
:集合是
java
中提供的⼀种容器,可以⽤来存储多个数据。
集合和数组既然都是容器,它们有啥区别呢?
数组的⻓度是固定的。集合的⻓度是可变的。
数组中存储的是同⼀类型的元素,可以存储基本数据类型值。集合存储的都是对象。⽽且对象的类
型可以不⼀致。在开发中⼀般当对象多的时候,使⽤集合进⾏存储。
1.2
集合框架
JAVASE
提供了满⾜各种需求的
API
,在使⽤这些
API
前,先了解其继承与接⼝操作架构,才能了解何时采
⽤哪个类,以及类之间如何彼此合作,从⽽达到灵活应⽤。
集合按照其存储结构可以分为两⼤类,分别是单列集合
java.util.Collection
和双列集
合
java.util.Map
,今天我们主要学习
Collection
集合,在
day04
时讲解
Map
集合。
Collection
:单列集合类的根接⼝,⽤于存储⼀系列符合某种规则的元素,它有两个重要的⼦接
⼝,分别是
java.util.List
和
java.util.Set
。其中,
List
的特点是元素有序、元素可重
复。
Set
的特点是元素⽆序,⽽且不可重复。
List
接⼝的主要实现类有
java.util.ArrayList
和
java.util.LinkedList
,
Set
接⼝的主要实现类有
java.util.HashSet
和
java.util.TreeSet
。
从上⾯的描述可以看出
JDK
中提供了丰富的集合类库,为了便于初学者进⾏系统地学习,接下来通过⼀
张图来描述整个集合类的继承体系。
集合本身是⼀个⼯具,它存放在
java.util
包中。在
Collection
接⼝定义着单列集合框架中最最共性的
内容。
1.3 Collection
常⽤功能
Collection
是所有单列集合的⽗接⼝,因此在
Collection
中定义了单列集合
(List
和
Set)
通⽤的⼀些⽅法,
这些⽅法可⽤于操作所有的单列集合。⽅法如下:
public boolean add(E e)
:
把给定的对象添加到当前集合中 。
public void clear()
:
清空集合中所有的元素。
public boolean remove(E e)
:
把给定的对象在当前集合中删除。
public boolean contains(E e)
:
判断当前集合中是否包含给定的对象。
public boolean isEmpty()
:
判断当前集合是否为空。
public int size()
:
返回集合中元素的个数。
public Object[] toArray()
:
把集合中的元素,存储到数组中。
⽅法演示:
import
java
.
util
.
ArrayList
;
import
java
.
util
.
Collection
;
public class
Demo1Collection
{
public static
void
main
(
String
[]
args
) {
//
创建集合对象
//
使⽤多态形式
Collection
<
String
>
coll
=
new
ArrayList
<
String
>
();
//
使⽤⽅法
//
添加功能
boolean add(String s)
coll
.
add
(
"
⼩李⼴
"
);
tips:
有关
Collection
中的⽅法可不⽌上⾯这些,其他⽅法可以⾃⾏查看
API
学习。
第⼆章
Iterator
迭代器
2.1 Iterator
接⼝
在程序开发中,经常需要遍历集合中的所有元素。针对这种需求,
JDK
专⻔提供了⼀个接⼝
java.util.Iterator
。
Iterator
接⼝也是
Java
集合中的⼀员,但它与
Collection
、
Map
接⼝有所
不同,
Collection
接⼝与
Map
接⼝主要⽤于存储元素,⽽
Iterator
主要⽤于迭代访问(即遍
历)
Collection
中的元素,因此
Iterator
对象也被称为迭代器。
想要遍历
Collection
集合,那么就要获取该集合迭代器完成迭代操作,下⾯介绍⼀下获取迭代器的⽅
法:
public Iterator iterator()
:
获取集合对应的迭代器,⽤来遍历集合中的元素的。
下⾯介绍⼀下迭代的概念:
迭代
:即
Collection
集合元素的通⽤获取⽅式。在取元素之前先要判断集合中有没有元素,如果
有,就把这个元素取出来,继续在判断,如果还有就再取出出来。⼀直把集合中的所有元素全部取
coll
.
add
(
"
扫地僧
"
);
coll
.
add
(
"
⽯破天
"
);
System
.
out
.
println
(
coll
);
// boolean contains(E e)
判断
o
是否在集合中存在
System
.
out
.
println
(
"
判断
扫地僧 是否在集合中
"
+
coll
.
contains
(
"
扫地僧
"
));
//boolean remove(E e)
删除在集合中的
o
元素
System
.
out
.
println
(
"
删除⽯破天:
"
+
coll
.
remove
(
"
⽯破天
"
));
System
.
out
.
println
(
"
操作之后集合中元素
:"
+
coll
);
// size()
集合中有⼏个元素
System
.
out
.
println
(
"
集合中有
"
+
coll
.
size
()
+
"
个元素
"
);
// Object[] toArray()
转换成⼀个
Object
数组
Object
[]
objects
=
coll
.
toArray
();
//
遍历数组
for
(
int
i
=
0
;
i
<
objects
.
length
;
i
++
) {
System
.
out
.
println
(
objects
[
i
]);
}
// void clear()
清空集合
coll
.
clear
();
System
.
out
.
println
(
"
集合中内容为:
"
+
coll
);
// boolean isEmpty()
判断是否为空
System
.
out
.
println
(
coll
.
isEmpty
());
}
}
出。这种取出⽅式专业术语称为迭代。
Iterator
接⼝的常⽤⽅法如下:
public E next()
:
返回迭代的下⼀个元素。
public boolean hasNext()
:
如果仍有元素可以迭代,则返回
true
。
接下来我们通过案例学习如何使⽤
Iterator
迭代集合中元素:
tips:
:在进⾏集合元素取出时,如果集合中已经没有元素了,还继续使⽤迭代器的
next
⽅法,将
会发⽣
java.util.NoSuchElementException
没有集合元素的错误。
2.2
迭代器的实现原理
我们在之前案例已经完成了
Iterator
遍历集合的整个过程。当遍历集合时,⾸先通过调⽤
t
集合的
iterator()
⽅法获得迭代器对象,然后使⽤
hashNext()
⽅法判断集合中是否存在下⼀个元素,如果存在,
则调⽤
next()
⽅法将元素取出,否则说明已到达了集合末尾,停⽌遍历元素。
Iterator
迭代器对象在遍历集合时,内部采⽤指针的⽅式来跟踪集合中的元素,为了让初学者能更好地
理解迭代器的⼯作原理,接下来通过⼀个图例来演示
Iterator
对象迭代元素的过程:
public class
IteratorDemo
{
public static
void
main
(
String
[]
args
) {
//
使⽤多态⽅式 创建对象
Collection
<
String
>
coll
=
new
ArrayList
<
String
>
();
//
添加元素到集合
coll
.
add
(
"
串串星⼈
"
);
coll
.
add
(
"
吐槽星⼈
"
);
coll
.
add
(
"
汪星⼈
"
);
//
遍历
//
使⽤迭代器 遍历
每个集合对象都有⾃⼰的迭代器
Iterator
<
String
>
it
=
coll
.
iterator
();
//
泛型指的是 迭代出 元素的数据类型
while
(
it
.
hasNext
()){
//
判断是否有迭代元素
String
s
=
it
.
next
();
//
获取迭代出的元素
System
.
out
.
println
(
s
);
}
}
}
在调⽤
Iterator
的
next
⽅法之前,迭代器的索引位于第⼀个元素之前,不指向任何元素,当第⼀次调⽤
迭代器的
next
⽅法后,迭代器的索引会向后移动⼀位,指向第⼀个元素并将该元素返回,当再次调⽤
next
⽅法时,迭代器的索引会指向第⼆个元素并将该元素返回,依此类推,直到
hasNext
⽅法返回
false
,表示到达了集合的末尾,终⽌对元素的遍历。
2.3
增强
for
增强
for
循环
(
也称
for each
循环
)
是
JDK1.5
以后出来的⼀个⾼级
for
循环,专⻔⽤来遍历数组和集合的。它
的内部原理其实是个
Iterator
迭代器,所以在遍历的过程中,不能对集合中的元素进⾏增删操作。
格式:
它⽤于遍历
Collection
和数组。通常只进⾏遍历元素,不要在遍历的过程中对集合元素进⾏增删操作。
练习
1
:遍历数组
for
(
元素的数据类型
变量
:
Collection
集合
or
数组
){
//
写操作代码
}
练习
2:
遍历集合
tips:
新
for
循环必须有被遍历的⽬标。⽬标只能是
Collection
或者是数组。新式
for
仅仅作为遍历操
作出现。
第三章 泛型
3.1
泛型概述
在前⾯学习集合时,我们都知道集合中是可以存放任意对象的,只要把对象存储集合后,那么这时他们
都会被提升成
Object
类型。当我们在取出每⼀个对象,并且进⾏相应的操作,这时必须采⽤类型转换。
⼤家观察下⾯代码:
public class
NBForDemo1
{
public static
void
main
(
String
[]
args
) {
int
[]
arr
=
{
3
,
5
,
6
,
87
};
//
使⽤增强
for
遍历数组
for
(
int
a
:
arr
){
//a
代表数组中的每个元素
System
.
out
.
println
(
a
);
}
}
}
public class
NBFor
{
public static
void
main
(
String
[]
args
) {
Collection
<
String
>
coll
=
new
ArrayList
<
String
>
();
coll
.
add
(
"
⼩河神
"
);
coll
.
add
(
"
⽼河神
"
);
coll
.
add
(
"
神婆
"
);
//
使⽤增强
for
遍历
for
(
String
s
:
coll
){
//
接收变量
s
代表 代表被遍历到的集合元素
System
.
out
.
println
(
s
);
}
}
}
public class
GenericDemo
{
public static
void
main
(
String
[]
args
) {
Collection coll
=
new
ArrayList
();
coll
.
add
(
"abc"
);
coll
.
add
(
"itcast"
);
coll
.
add
(
5
);
//
由于集合没有做任何限定,任何类型都可以给其中存放
Iterator it
=
coll
.
iterator
();
while
(
it
.
hasNext
()){
//
需要打印每个字符串的⻓度
,
就要把迭代出来的对象转成
String
类型
String
str
=
(
String
)
it
.
next
();
程序在运⾏时发⽣了问题
java.lang.ClassCastException
。
为什么会发⽣类型转换异常呢?
我们来分析下:由于集合中什么类型的元素都可以存储。导致取出时强转引发运⾏时
ClassCastException
。
怎么来解决这个问题呢?
Collection
虽然可以存储各种对象,但实际上通常
Collection
只存储同⼀类型对象。例如都是存储字符串
对象。因此在
JDK5
之后,新增了
泛型
(
Generic
)
语法,让你在设计
API
时可以指定类或⽅法⽀持泛型,这
样我们使⽤
API
的时候也变得更为简洁,并得到了编译时期的语法检查。
泛型
:可以在类或⽅法中预⽀地使⽤未知的类型。
tips:
⼀般在创建对象时,将未知的类型确定具体的类型。当没有指定泛型时,默认类型为
Object
类型。
3.2
使⽤泛型的好处
上⼀节只是讲解了泛型的引⼊,那么泛型带来了哪些好处呢?
将运⾏时期的
ClassCastException
,转移到了编译时期变成了编译失败。
避免了类型强转的麻烦。
通过我们如下代码体验⼀下:
tips:
泛型是数据类型的⼀部分,我们将类名与泛型合并⼀起看做数据类型。
第四章 集合综合案例
System
.
out
.
println
(
str
.
length
());
}
}
}
public class
GenericDemo2
{
public static
void
main
(
String
[]
args
) {
Collection
<
String
>
list
=
new
ArrayList
<
String
>
();
list
.
add
(
"abc"
);
list
.
add
(
"itcast"
);
// list.add(5);//
当集合明确类型后,存放类型不⼀致就会编译报错
//
集合已经明确具体存放的元素类型,那么在使⽤迭代器的时候,迭代器也同样会知道具体遍
历元素类型
Iterator
<
String
>
it
=
list
.
iterator
();
while
(
it
.
hasNext
()){
String
str
=
it
.
next
();
//
当使⽤
Iterator<String>
控制元素类型后,就不需要强转了。获取到的元素直接就是
String
类型
System
.
out
.
println
(
str
.
length
());
}
}
}
第四章 集合综合案例
4.1
案例介绍
按照⽃地主的规则,完成洗牌发牌的动作。
具体规则:
使⽤
54
张牌打乱顺序
,
三个玩家参与游戏,三⼈交替摸牌,每⼈
17
张牌,最后三张留作底牌。
4.2
案例分析
准备牌:
牌可以设计为⼀个
ArrayList,
每个字符串为⼀张牌。
每张牌由花⾊数字两部分组成,我们可以使⽤花⾊集合与数字集合嵌套迭代完成每张牌的组装。
牌由
Collections
类的
shuffle
⽅法进⾏随机排序。
发牌
将每个⼈以及底牌设计为
ArrayList,
将最后
3
张牌直接存放于底牌,剩余牌通过对
3
取模依次发牌。
看牌
直接打印每个集合。
4.3
代码实现
import
java
.
util
.
ArrayList
;
import
java
.
util
.
Collections
;
public class
Poker
{
public static
void
main
(
String
[]
args
) {
/*
* 1:
准备牌操作
*/
//1.1
创建牌盒 将来存储牌⾯的
ArrayList
<
String
>
pokerBox
=
new
ArrayList
<
String
>
();
//1.2
创建花⾊集合
ArrayList
<
String
>
colors
=
new
ArrayList
<
String
>
();
//1.3
创建数字集合
ArrayList
<
String
>
numbers
=
new
ArrayList
<
String
>
();
//1.4
分别给花⾊ 以及 数字集合添加元素
colors
.
add
(
"
♥
"
);
colors
.
add
(
"
♦
"
);
colors
.
add
(
"
♠
"
);
colors
.
add
(
"
♣
"
);
for
(
int
i
=
2
;
i
<=
10
;
i
++
){
numbers
.
add
(
i
+
""
);
}
numbers
.
add
(
"J"
);
numbers
.
add
(
"Q"
);
numbers
.
add
(
"K"
);
numbers
.
add
(
"A"
);
//1.5
创造牌
拼接牌操作
//
拿出每⼀个花⾊
然后跟每⼀个数字 进⾏结合
存储到牌盒中
for
(
String
color
:
colors
) {
//color
每⼀个花⾊
//
遍历数字集合
for
(
String
number
:
numbers
){
//
结合
String
card
=
color
+
number
;
//
存储到牌盒中
pokerBox
.
add
(
card
);
}
}
//1.6
⼤王⼩王
pokerBox
.
add
(
"
⼩
☺
"
);
pokerBox
.
add
(
"
⼤
☠
"
);
// System.out.println(pokerBox);
//
洗牌 是不是就是将
牌盒中 牌的索引打乱
// Collections
类
⼯具类
都是 静态⽅法
// shuffer
⽅法
/*
* static void shuffle(List<?> list)
*
使⽤默认随机源对指定列表进⾏置换。
*/
//2:
洗牌
Collections
.
shuffle
(
pokerBox
);
//3
发牌
//3.1
创建 三个 玩家集合
创建⼀个底牌集合
ArrayList
<
String
>
player1
=
new
ArrayList
<
String
>
();
ArrayList
<
String
>
player2
=
new
ArrayList
<
String
>
();
ArrayList
<
String
>
player3
=
new
ArrayList
<
String
>
();
ArrayList
<
String
>
dipai
=
new
ArrayList
<
String
>
();
//
遍历 牌盒
必须知道索引
for
(
int
i
=
0
;
i
<
pokerBox
.
size
();
i
++
){
//
获取 牌⾯
String
card
=
pokerBox
.
get
(
i
);
//
留出三张底牌 存到 底牌集合中
if
(
i
>=
51
){
//
存到底牌集合中
dipai
.
add
(
card
);
}
else
{
//
玩家
1 %3 ==0
if
(
i
%
3
==
0
){
player1
.
add
(
card
);
}
else if
(
i
%
3
==
1
){
//
玩家
2
player2
.
add
(
card
);
}
else
{
//
玩家
3
player3
.
add
(
card
);
}
}
}
//
看看
System
.
out
.
println
(
"
令狐冲:
"
+
player1
);
System
.
out
.
println
(
"
⽥伯光:
"
+
player2
);
System
.
out
.
println
(
"
绿⽵翁:
"
+
player3
);
System
.
out
.
println
(
"
底牌:
"
+
dipai
);
}
}