目录
1. Collection接口
Collection接口是Collection体系的根接口,定义了单值元素的容器,其下有List、Set、Queue三个重要的接口。
· List:列表接口,存储有序、允许重复的、有下标的元素;
· Set:集合接口,存储无序、不允许重复、无下标的元素;
· Queue:队列接口,存储有序的、无下标的、允许重复的元素。
1)Collection接口实现的接口:
Collection实现了Iterable接口,可通过迭代器Iterator、foreach循环遍历。
2)Collection接口中的方法(常用):
· boolean add(Object obj) // 添加一个对象
· boolean addAll(Collection C) // 将一个集合C中的元素全部添加到另一个集合
· void clear() // 清空此集合中的所有元素
· boolean contains(Object o) // 检查此集合中是否包含o对象
· boolean equals(Object o) // 判断此集合是否与当前对象相等
· boolean isEmpty() // 判断此集合是否为空
· boolean remove(Object o) // 在此集合中移除o对象
· int size() // 返回集合中元素的个数
· Object[] toArray() // 将此集合转换为数组
注意:同一个实现Collection接口的容器智能存储相同类型的元素,对于不同类型的元素,可以通过将泛型修改为Object的方式进行存储。
3)遍历元素:
可以采用iterator迭代器遍历容器中的元素,或者采用增强for循环:
public class Test {
public static void main(String[] args){
Collection<Object> collection = new ArrayList<>();
// 添加元素
collection.add("芒果");
collection.add("榴莲");
collection.add("西瓜");
// 遍历元素
// 1. 迭代器遍历
// 调用iterator()方法获取迭代器
Iterator<Object> iterator = collection.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
// 2. forEach循环遍历
for (Object o:collection) {
System.out.println(o.toString());
}
}
}
1.1 List子接口
1)List接口的特点:线性表接口,有序(元素的添加顺序与获取/遍历顺序一致),有下标(可以通过下标访问),允许元素重复。
2)List接口实现的接口:
List接口实现了 Collection 接口与 Iterabel 接口。
3)List接口中的新方法:
· void add(int index, Object o) // 在index位置插入对象o
· boolean addAll(int index, Collection c) // 将一个集合中的元素添加到此集合中index的位置,其余元素依次后移
· Object get(int index) // 放回集合中指定位置的元素
· List subList(int fromIndex, int toIndex) // 返回fromIndex与toIndex之间的集合元素
· ListIterator listIterator() // 返回一个ListIterator迭代器(功能更强大)
4)ListIterator迭代器:
与Iterator迭代器相比,ListIterator迭代器可以向前、向后添加、修改、删除元素。
public class Test {
public static void main(String[] args){
List<Object> list = new ArrayList<>();
// 添加元素
list.add("芒果");
list.add("榴莲");
list.add("西瓜");
// 迭代器遍历
// 调用listIterator()方法获取列表迭代器
ListIterator<Object> listIterator = list.listIterator();
// 从前向后遍历
while ( listIterator.hasNext()){
System.out.println( listIterator.nextIndex()+":"+listIterator.next());
}
// 从后向前遍历
while (listIterator.hasPrevious()){
System.out.println( listIterator.previousIndex()+":"+listIterator.previous());
}
}
}
5)List接口的实现类
· ArrayList:底层采用数组(动态扩容)结构实现(默认大小10),因为有索引,查询修改快,增加删除慢。
源码分析:
默认容量 private static final int DEFAULT_CAPACITY = 10;
存放元素的数组 transient Object[] elementData;
数组元素个数:private int size;
注意:
1)初始化:
虽然ArrayList默认初始化容量为10的数组,但实际上ArrayList通过{}(空数组)进行的初始化,直到添加第一个元素时才会扩容为10。
2)size 与 length:
size返回的是底层数组中实际上有多少个元素,length返回的是数组的容量。
3)扩容:
ArrayList是通过grow()函数进行扩容,扩容的本质是将数组拷贝到另一个更大容量的数组(最小扩容为+1,最优扩容为扩容为原数组的1.5倍))。
· LinkedList:底层采用双向链表实现,没有索引,增加删除快,查询慢。
源码分析:
transient int size = 0; // 链表中的元素个数
transient Node<E> first; // 头指针
transient Node<E> last; // 尾指针
注意:
1)LinkedList底层虽然没有索引,但提供了通过index访问链表节点的方式,通过indexof(Object obj)访问元素的索引,通过get(int index)获取对应索引的元素。
2)LinkedList中提供了iterator、listIterator两种迭代器,其中listIterator允许逆序遍历。
3)LinkedList底层采用链表实现,无序开辟连续的存储空间,查询快,增删慢;ArrayList底层采用动态扩容的数组实现,需要开辟连续的存储空间,查询慢,增删快。
· Vector:底层采用数组结构实现因为有索引,查询修改快,增加删除慢。
注意:
1)Vector有子类Stack,因此栈的底层也是采用数组实现的。
2)与ArrayList相比,Vector虽然也是采用数组,但其运行效率低,是线程安全的。
1.2 泛型
1)概述:
泛型是JDK1.5引入的一个新特性,其本质是参数化类型,将类型作为参数传递。
2)语法:
<T ,...> // T称为类型占位符,表示一种引用类型(任意引用类型均可以匹配)。
T:type类型
E:element元素
k:key键
V:value值
注意:只有引用类型可以作为泛型的参数出现,基本数据类型需要转换为其对应的包装类型。
3)泛型使用:
· 泛型类:在类名之后声明泛型(类名<T>)
public class Test {
public static void main(String[] args) {
// 使用泛型类MyGeneric创建对象
MyGeneric<String> myGeneric = new MyGeneric<String>();
// 调用set方法
myGeneric.setT("Hello");
// 调用get方法
System.out.println(myGeneric.getT());
}
static class MyGeneric<T>{
// 使用泛型
// 1.创建变量
private T t;
// 2.泛型作为方法参数
public void setT(T t){
this.t = t;
}
// 3.作为方法的返回值
public T getT(){
return t;
}
}
}
注意:在创建泛型类对象的时候要确定泛型对应的类型
· 泛型接口:在接口后声明泛型(接口名<T>)
public class Test {
public static void main(String[] args) {
// 使用泛型类MyGeneric创建对象
MyGeneric<String> myGeneric = new MyGenericImpl();
// 调用set方法
myGeneric.setT("Hello");
// 调用get方法
System.out.println(myGeneric.getT());
}
// 泛型接口
interface MyGeneric<T>{
// 使用泛型
// 1.做为方法返回值
T getT();
// 2.做方法参数
void setT(T t);
}
// 实现类
// 在实现泛型接口的时候就必须确定泛型对应的类型
static class MyGenericImpl implements MyGeneric<String>{
private String s;
@Override
public String getT() {
return s;
}
@Override
public void setT(String s) {
this.s = s;
}
}
}
注意:在实现泛型接口的时候需要确定泛型实际使用的参数。
· 泛型方法:在返回值类型前声明泛型(<T> 返回值类型)
public class Test {
// 泛型方法
// T 表示传入参数的类型不确定
public <T> void show(T t){
System.out.println("泛型方法"+t);
}
}
4)泛型的好处:
· 提高代码的重用性;
· 防止类型转换异常,提高代码的安全性;
1.3 Set子接口
1)Set接口的特点:集合接口,无序(元素的添加顺序与获取/遍历顺序不一致),无下标(不可以通过下标访问),不允许元素重复(最多包含一个null)。
2)Set接口实现的接口:
Set接口实现了 Collection 接口与 Iterabel 接口。
3)Set接口中的新方法:
Set接口中的方法全部继承自Collection方法,其本身并没有定义新方法。
4)Set的实现类:
· HashSet:基于哈希表(数组+链表+红黑树)实现的Set集合;通过Hashcode保证了集合中的元素不重复,当存入元素的hashCode相同时,会调用equals进行确认,如果结果为true,则拒绝后者进入。
Hashset底层是通过HashMap实现的,其无参构造方法默认调用HashMap的无参构造方法,初始化一个容量为16,扩容因子为0.75的散列表。
/**
* Constructs a new, empty set; the backing <tt>HashMap</tt> instance has
* default initial capacity (16) and load factor (0.75).
*/
public HashSet() {
map = new HashMap<>();
}
HashSet的存储过程:
1. 根据hascode计算保存的位置,如果位置为空则直接保存,不为空执行下一步;
2. 执行equals方法,如果equals方法为true,则认为是重复,否则形成链表。
3. 当填入元素 > 散列表长度*扩容因子时,触发扩容机制,通过位移运算将散列表的长度翻倍。
4. 当 链表长度>8 时,将链表转换为红黑树以提高查询效率。
· TreeSet(红黑树):基于二叉树实现的Set集合;通过排列顺序实现了元素不重复;其实现了SortedSet接口,对集合元素自动排序;其要求元素对象的类型必须实现Comparable接口,指定排序规则,并通过CompareTo方法确定是否为重复元素。
TreeSet的底层采用TreeMap实现,其存储结构为红黑树,其无参构造方法默认调用TreeMap的无参构造方法,初始化一个comparator = null的TreeMap。
/**
* Constructs a new, empty tree map, using the natural ordering of its keys.
* All keys inserted into the map must implement the Comparable interface.
*/
public TreeMap() {
comparator = null;
}
TreeSet的使用:
注意:
TreeSet 与 HashSet 有且仅有 iterator一个迭代器。