# finally -> 02 【Collection、泛型】
## 1.集合
### 1.1集合与数组
##### 集合的概述:
1. 数组是一种容器,集合也是一种容器,都可以存放多个数据。
2. 数组的长度一旦确定,运行期间不可改变;但是大多数集合的长度可以变化。
3. 曾经已经学习过的ArrayList类,只是多种集合当中的一种而已。
4. 数组当中的数据类型必须统一,但是集合当中的元素“可选统一”。
创建集合的时候,可以写一个泛型<>,代表集合当中统一的数据类型是什么。
如果集合创建的时候,没有写<>,那么所有数据类型都可以放进来,都将会处理成为Object。
### 1.2 Collection接口常用方法
java.util.Collection接口当中规定的常用集合方法有:
public boolean add(E e):把指定的参数元素,添加到集合中;返回添加动作是否成功。
public boolean remove(Object e):根据参数指定的元素内容,从集合当中删除元素;返回删除是否成功。
public boolean contains(Object e):判断集合是否包含指定的元素。
public boolean isEmpty():判断集合是否为空白(一个元素都没有)。
public void clear():清空集合当中所有的元素内容。
public int size():获取集合的长度尺寸。
public Object[] toArray():将集合转换成为数组形式。
##### `注意事项`:
对于remove方法和contains方法来说,参数是Object类型。这里是如何得知两个对象是否“相同”的呢?由equals和hashCode两个方法共同决定。
### 1.3迭代器
并不是所有的集合都有索引值,所以对于Collection接口来说,普通的for循环索引i那种方式不一定适用。
有一个叫做“迭代器”的小东东,非常好用,专门用来遍历集合的。无论是什么集合,只要是Collection的实现类,都可以用。
##### `使用步骤:`
1. 根据集合获取一个对应的迭代器(注意不是自己new的,而是从集合当中获取的。)
2. 通过迭代器,看看有没有下一个。
3. 如果有下一个,通过迭代器获取下一个,并且向后移动一个位置。
4. 上述2-3步骤是一个循环,直到没有下一个为止。(while循环。)
java.util.Iterator<T>接口代表迭代器,其中有两个常用的方法:
boolean hasNext():`判断有没有下一个元素``
T next():获取下一个,并且向后移动一个位置
##### 注意:
在使用迭代器遍历集合的过程当中,一定要避免直接通过集合改变其中元素的个数。否则就会导致ConcurrentModificationException并发修改异常。
### 1.4增强for循环
增强for循环(昵称也叫做for-each循环)是JDK 1.5添加的特性之一。
for (数据类型 变量名称 : 数组) {
// ...
}
其中的数据类型并不一定是int,不代表索引值。
含义:用左边的变量,分别得到右侧数组当中的每一个数据值。
##### 备注:
这其实只是一个语法糖。对于数组来说,增强for循环底层其实就是一个普通的for循环。
增强for循环照样也可以支持集合。
for (数据类型 变量名称 : 集合) {
// ...
}
##### 备注:
这其实也是一种语法糖,对于集合来说,底层其实就是迭代器,只是表面上增强for循环的写法简单而已。
##### 在使用增强for循环的时候,注意事项:
1. 支持数组,其实是一个语法糖,底层就是普通的fori循环。
2. 支持java.lang.Iterable接口对象,其中就包含了集合。因为这个接口规定了一项能力:
public Iterator<T> iterator():获取迭代器的方法。
3. 支持集合,也是一个语法糖。底层就是在使用迭代器。
4. 增强for循环当中没有索引值,所以就无法直接修改数组或集合中的内容。【重点】
`基本数据类型存储的就是数据值`,
`引用数据类型存储的是地址值`。
##### 备注:
集合当中保存的其实都是对象的【地址值】。
增强for循环没有索引值,所以基本数据类型的数据值不能变,同时引用数据类型的地址值不能变
## 2.泛型
### 2.1泛型概述
##### 使用泛型的好处:
1. 保证类型统一,确保类型安全。
2. 将可能发生的类型安全问题,从运行期提前到编译期。(有问题尽量在javac的时候就暴露出来最好,别等到java运行时再暴露)
3. 省去向下转型的麻烦。
4. 让代码模板化。
##### `自定义泛型的三种用法`:
1. 泛型类
2. 泛型接口
3. 泛型方法
### 2.2泛型类定义
自定义一个泛型类
修饰符 class 类名称<泛型> {
// ...
}
泛型的名称用什么都可以,一般推荐使用大写字母。
泛型代表一种尚不确定的类型,所有本类范围之内都能用这个泛型当做不确定的类型进行使用。
什么时候才能确定这个泛型?
当创建泛型类对象的时候,就可以确定。
##### 定义一个泛型接口
修饰符 interface 接口名称<泛型> {
// ...
}
含义和泛型类是完全相同的:本接口之内泛型通用。
##### `时候确定接口的泛型`
1. 实现类在实现接口的时候,直接指定具体泛型。
2. 实现类仍然不指定具体泛型,那么实现类也必须是一个泛型类。
##### 注意:
对于泛型类/泛型接口来说,泛型是在本类/本接口当中全局通用。
##### `泛型方法的格式:`
修饰符 <泛型> 返回值类型 方法名称(参数类型 参数名称) {
方法体
}
##### 备注:
这个泛型定义在方法上,所以只有当前这个方法自己专用。别人不能用。
### 2.3泛型的通配符
泛型的通配符其实就是一个问号:【?】
作用:用来被动匹配任何一种泛型。
##### 注意事项:
1. 一旦使用了泛型?通配符进行匹配接收,那么遍历的时候就只能当做Object,因为不确定泛型到底传进来的是谁。
2. 这个通配符问号,只能在匹配接收的时候使用,不能在定义泛型的时候使用。
对于泛型的通配符问号,有两种特殊写法:
##### 上下限,上下界。
##### <?>:随便,谁都行。
<? extends 类>:可以是指定的类,或者其子类。(上限,最高不能超过这个类。)
<? super 类>:可以是指定的类,或者其父类。(下限,最低不能超过这个类。)