文章目录
Collection与其子接口
前言
Collection接口是在整个Java类集中最大的单值操作父接口,它下面还包含一些子类。
所谓单值操作指的是该接口每次只能存储一个数据。
Collection方法
Collection包含的常用方法如下:
No. | 方法名称 | 类型 | 描述 |
---|---|---|---|
1 | public boolean add(E e) | 普通 | 向集合中插入一个元素 |
2 | public boolean addAll(Collection<? extends E> c) | 普通 | 向集合中插入一组元素 |
3 | public void clear() | 普通 | 清空集合中的元素 |
4 | public boolean contains(Object o) | 普通 | 查找一个元素是否存在 |
5 | public boolean containsAll(Collection<?> c) | 普通 | 查找一组元素是否存在 |
6 | public boolean isEmpty() | 普通 | 判断集合是否为空 |
7 | public Iterator iterator() | 普通 | 为 Iterator 接口实例化 |
8 | public boolean remove(Object o) | 普通 | 从集合中删除一个对象 |
9 | boolean removeAll(Collection<?> c) | 普通 | 从集合中删除一组对象 |
10 | boolean retainAll(Collection<?> c) | 普通 | 判断是否没有指定的集合 |
11 | public int size() | 普通 | 求出集合中元素的个数 |
12 | public Object[] toArray() | 普通 | 以对象数组的形式返回集合中的全部内容 |
13 | T[] toArray(T[] a) | 普通 | 指定操作的泛型类型,并把内容返回 |
14 | public boolean equals(Object o) | 普通 | 从 Object 类中覆写而来 |
15 | public int hashCode() | 普通 | 从 Object 类中覆写而来 |
我们一般不直接使用Collection接口,而是使用它的两个子接口:List,Set。
作为子接口,当然也全部继承Collection的全部方法和特性,比如全部是单值存储。当然有些方法在继承后被重写了。
List接口
List接口的特点是里面存储的内容是允许重复的。
定义:
public interface List<E> extends Collection<E>
List接口中的方法
List接口中有如下10个方法是对Collection接口进行扩充:
No. | 方法名称 | 类型 | 描述 |
---|---|---|---|
1 | public void add(int index,E element) | 普通 | 在指定位置处增加元素 |
2 | boolean addAll(int index,Collection<? extends E> c) | 普通 | 在指定位置处增加一组元素 |
3 | public E get(int index) | 普通 | 根据索引位置取出每一个元素 |
4 | public int indexOf(Object o) | 普通 | 根据对象查找指定的位置,找不到返回-1 |
5 | public int lastIndexOf(Object o) | 普通 | 从后面向前查找位置,找不到返回-1 |
6 | public ListIterator listIterator() | 普通 | 返回 ListIterator 接口的实例 |
7 | public ListIterator listIterator(int index) | 普通 | 返回从指定位置的 ListIterator 接口的实例 |
8 | public E remove(int index) | 普通 | 获取并删除指定位置的内容 |
9 | public E set(int index,E element) | 普通 | 修改指定位置的内容 |
10 | List subList(int fromIndex,int toIndex) | 普通 | 返回子集合 |
当然,List作为一个接口,必须要用实现类才能实现它的意义。常用的实现类有如下几个:
- ArrayList(95%)
- Vector(4%)
- LinkList(1%)
ArrayList、Vector、LinkList的区别:
- ArrayList线程异步、线程不安全,Vector线程同步、线程安全
- ArrayList、Vector是基于动态数组的实现,LinkList是基于链表的实现
ArrayList类
前序:
基于数组结构实现,对于操作数据增加删除慢,查找快。
实现
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, Serializable
AbstractList是 List 接口的子类。AbstractList 是个抽象类,适配器设计模式。
我们一般实例化对象和指定泛型类型就如下:
ArrayList<Integer> data = new ArrayList<>();
ArrrayList有三种构造方法:
构造器 | 描 |
---|---|
ArrayList() | 构造一个初始容量为10的空列表。 |
ArrayList(int initialCapacity) | 构造具有指定初始容量的空列表。 |
ArrayList(Collection<? extends E> c) | 按照集合的迭代器返回的顺序构造一个包含指定集合元素的列表。 |
注意:使用ArrayList()构造方法时,初始容量刚开始并不是为10;
刚开始在没存数据之前,其实容量为0,存数据时会进入判断,当前容量1.5倍小于等于当前容量加1时(newCapacity - minCapacity <= 0),如果数组是第一次存入数据,容量就会动态扩展到10;
在以上构造方法中,如果但数据存不下去时,数组长度就会扩展1.5倍(newCapacity = oldCapacity+(oldCapacity >> 1))(>>1:二进制右移一位)
Vector类
前序
从Java1.2开始该类才得以改进实现List接口,使用的也是数组结构;
Vector线程同步某一个时刻只有一个线程能够编写Vector,线程安全但速度慢;
如果不需要线程安全实现,则建议使用ArrayList,速度更快;
实现
public class Vector<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, Serializable
AbstractList是 List 接口的子类。AbstractList 是个抽象类,适配器设计模式。
我们一般实例化对象和指定泛型类型就如下:
Vector<Integer> data = new Vector<>();
构造方法
构造器 | 描述 |
---|---|
Vector() | 构造一个空向量,使其内部数据数组的大小为 10 ,其标准容量增量为零。 |
Vector(int initialCapacity) | 构造一个具有指定初始容量且容量增量等于零的空向量。 |
Vector(int initialCapacity, int capacityIncrement) | 构造具有指定初始容量和容量增量的空向量。 |
Vector(Collection<? extends E> c) | 按照集合的迭代器返回的顺序构造一个包含指定集合元素的向量。 |
Vector可以指定增量大小,如果增量为0,则扩容算法是翻一番。
Vector 类和 ArrayList 类的区别
这两个类虽然都是 List 接口的子类,但是使用起来有如下的区别,为了方便大家笔试,列出此内容:
No. | 区别点 | ArrayList | Vector |
---|---|---|---|
1 | 时间 | 是新的类, | 是在 JDK 1.2 之后推出的 是旧的类是在 JDK 1.0 的时候就定义的 |
2 | 性能 | 性能较高,是采用了异步处理 | 性能较低,是采用了同步处理 |
3 | 输出 | 支持 Iterator、ListIterator 输出 | 除了支持 Iterator、 |
LinkedList类
前序
LinkedList使用的是双向链表结构,对于增加删除快,查找则慢;
这种类的使用情况非常少;
实现
public class LinkedList<E> extends AbstractSequentialList<E> implements List<E>,Deque<E>, Cloneable, Serializable
此类继承了 AbstractList,所以是 List 的子类。但是此类也是 Queue 接口的子类,Queue 接口定义了如下的方法:
No. | 方法名称 | 类型 | 描述 |
---|---|---|---|
1 | public boolean add(E e) | 普通 | 增加元素,如果有容量限制,并且已满,则抛出异常 |
2 | public E element() | 普通 | 取得,但是不删除当前元素,如果对列为空则抛出异常 |
3 | boolean offer(E e) | 普通 | 添加,如果有容量限制,并且已满,只是无法添加,但不抛出异常,返回false |
4 | E peek() | 普通 | 取得头元素,但是不删除,如果队列为空,则返回null |
5 | E poll() | 普通 | 取得头元素,但是删除, 如果队列为空,则返回 null |
6 | E remove() | 普通 | 删除当前元素, 如果对列为空则抛出异常 |
我们一般实例化对象和指定泛型类型就如下:
LinkedList<Integer> data = new LinkList<>();
LinkedList可以用来模拟栈的数据结构
LinkedList<Integer> data = new LinkedList<>();
//压栈
data.push(100);
data.push(200);
//弹栈
Integer i = data.pop();
System.out.println(i);
LinkedList可以用来模拟队列(单端和双端)的数据结构
LinkedList<Integer> data = new LinkedList<>();
data.addFirst(100);
data.addFirst(200);
Integer i = data.removeLast();
System.out.println(i);
Set接口
前言
Set是Collection子接口,与 List 接口最大的不同在于,Set 接口不包含重复元素。
Set 接口并没有对 Collection 接口进行扩充,基本上还是与 Collection 接口保持一致。
在此接口中有两个常用的子类:HashSet、TreeSet
关于Set的元素
Set接口没有 List 接口中定义的 get(int index)方法,所以无法使用循环进行输出。想要获取数据有两个办法:
- 使用迭代器进行输出
- 使用toArray()转换为数组再进行遍历、输出
Set 接口不包含重复元素,而且为单值,null也只能存在一个。这样的形式可以模拟数学中’集‘的概念;
Set集合有一些子类在存储时散列存放的数据结构,当存储可变对象时需要非常小心,每个数据的位置由该数据计算得到,如果数据可修改,那么地址也会变化。
HashSet类
HashSet属于散列存放,使用哈希表结构进行存储数据。
HashSet<String> set = new HashSet<>();
使用HashSet存数据,其实是借用了HashMap(双值存储)的存储方式,一个值存要存的数据e,另一个值存指定的常量PRESENT;
HashSet存储元素输出没有规律,而且重复元素无法再次存入;
HashSet<String> set = new HashSet<>();
set.add("a");
set.add("b");
set.add("c");
set.add("a");
Iterator<String> iterator = set.iterator();
while(iterator.hashNext()){
System.out.print(iterator.next()+", ");
}
打印结果可能是:a, c, b,
TreeSet类
前序
TreeSet采用二叉树进行存储,是有序的;
内部存储和HashSet一样,是基于Map来存储数据的;
提供的方法和HashSet基本一样,只不过它们存储的数据结构不一样;
TreeSet的使用
TreeSet<String> data = new TreeSet<>();
打印出来的顺序是基于ASCII码进行先后排序的,如果数据不属于ASCII码,比如存储的是对象名,打印顺序就会出乱子。
那不属于的ASCII码的该如何比较呢:那就需要实现Comparable接口。
例如: