Java类集
一. Collection接口
collection接口继承于Iterable。
主要方法:
1)add:添加数据
2)addAll:添加一组数据
3)clear:清空数据
4)contains:是否包含某个对象
5)remove:移除某一项
6)size:获取集合长度
7)iterator:返回
在保存自定义类型的数据时,若使用contains和remove等方法时需要对数据进行比较的话,需要让自定义类型实现了equals方法。
二. List接口
扩充的方法:
1)get(int index):获取数据
2)set(int index,Object element):设置数据
3)listIterator
List有三个子类
ArrayList、LinkedList、Vector
ArrayList 类
继承结构
ArrayList的扩容机制:无参构造初始化时默认为空数组,当添加一个元素时,扩容到10,后面如果size超过10的话再1.5倍左右扩容(oldsize+oldsize/2)。有参构造则是按照参数的大小初始化数组,若数组大小不够时也是1.5倍左右扩容。
LinkedList 类
继承结构
ArrayList 类和 LinkedList 类的区别
- 因为 Array 是基于索引(index)的数据结构,它使用索引在数组中搜索和读取数据是很快的。Array 获取数据的时间复杂度是 O(1),但是要删除数据却是开销很大的,因为这需要重排数组中的所有数据。
- 相对于 ArrayList,LinkedList 插入是更快的。因为 LinkedList 不像 ArrayList 一样,不需要改变数组的大小,也不需要在数组装满的时候要将所有的数据重新装入一个新的数组,这是 ArrayList 最坏的一种情况,时间复杂度是 O(n),而 LinkedList 中插入或删除的时间复杂度仅为 O(1)。ArrayList 在插入数据时还需要更新索引(除了插入数组的尾部)。
- 类似于插入数据,删除数据时,LinkedList 也优于 ArrayList。
- LinkedList 需要更多的内存,因为 ArrayList 的每个索引的位置是实际的数据,而 LinkedList 中的每个节点中存储的是实际的数据和前后节点的位置。
Vector 类
Vector的继承关系和ArrayList是完全相同的。使用方法也完全相同。
扩容机制,调用默认的构造方法时,直接会给长度为10的数组。后期扩容时会扩容为原来的二倍。但是Vector的构造方法可以传入扩容的长度,当指定的长度大于0时,那么在扩容时不会扩容为2倍,而是在原来长度的基础上加上扩容的长度。
ArrayList 类和 Vector 类的区别
- Vector 是线程安全的,也就是说是同步的 ,而 ArrayList 是线程不安全的,不是同步的。
- 扩容时,Vector 默认增长为原来一倍 ,而 ArrayList 却是原来的 50% ,这样 ArrayList 就有利于节约内存空间。
说明:如果涉及到堆栈,队列等操作,应该考虑用 Vector,如果需要快速随机访问元素,应该使用 ArrayList
三. Set 接口
继承关系
set接口定义了集合中的元素不能有重复的元素
set有两个子类,分别是HashSet和TreeSet
HashSet 类
继承关系
HashSet中的元素是无序的。且其消除重复元素的原理是因为元素比较时用了hashcode和equals方法
TreeSet 类
继承结构
HashSet中的元素是有序的。
但是添加的元素是自定义类时,该自定义类必须实现Comparable接口,且必须将所有属性都进行比较。
四. 集合的四种输入方式
- Iterator迭代输出
Iterator<Integer> iterator = list.iterator();
while (iterator.hasNext()){
Integer next = iterator.next();
System.out.println(next);
}
collection和iterator中都有remove方法,如果在遍历的过程中要删除某一元素,不能使用collection中的remove,会报concurrentModificationException,使用iterator的remove方法则不会报异常。
- ListIterator双向迭代输出
ListIterator<Integer> iterator = list.listIterator();
while (iterator.hasNext()){
Integer next = iterator.next();
System.out.println(next);
}
while (iterator.hasPrevious()){
Integer next = iterator.previous();
System.out.println(next);
}
该接口为iterator的子接口,只适用于List的实现类,可以实现由后向前的遍历,但是其内部有指针在移动,要实现从后向前输出必须先从前向后输出,将指针移动到末尾才能从后向前输出。
- enumeration枚举输出
Enumeration<Integer> elements = vector.elements();
while (elements.hasMoreElements()){
System.out.println(elements.nextElement());
}
只为Vector提供服务,vector调用element方法获取enumeration对象
- 增强for循环
for (Integer integer : list) {
System.out.println(integer);
}
五. Map 接口
1)put(key,value):向map中添加元素
2)get(key):获取指定key的值
3)contains(key):查看是否存在指定的键
4)size():获取大小
5)containsValue(value):查看是否存在指定的值
6)remove(key):删除指定的键值
7)keySet():返回键的集合
8)entrySet():返回键值对的集合
。。。
map中的键不会重复,给同一个键赋值时,后边的值会覆盖前边的值。map中的一对键值可以转换为一个entry,在迭代遍历时,需要将map转换为entryset来实现遍历。在使用自定义类作为键时,必须让自定义类实现hashcode和equals方法。处理哈希冲突时,采用的是链地址法,将哈希值相同的元素都链到一起。
有四个子类:HashMap、HashTable、TreeMap、LinkedHashMap
HashMap 类
继承结构
HashMap存储时,默认是无序的。HashMap的默认容量大小为16,并且默认的加载因子为0.75,当存储的元素超过(容量*加载因子=threshold)时,那么哈希表就会进行扩容,每次扩容都会变味原来的二倍。hashmap默认采用数组存储,当发生冲突时会采用头插法在对应的数组位置拆入链表中,当链表长度超过阈值(8)时,会将链表转换为红黑树,此举是为了提高查询的时间复杂度,应对大数据时代。
LinkedHashMap 类
继承结构
LinkedHashMap存储时,默认是有序的。按照put顺序依次存储。
HashTable类
继承结构
使用和HashMap基本相同,但是HashTable存储时,键和值都不能为null,否则会抛异常
HashMap 和 HashTable 的区别
- HashMap 几乎可以等价于 HashTable,除了 HashMap 是非 synchronized 的,并可以接受 null(HashMap 可以接受为 null 的键值 (key) 和值 (value),而 HashTable 则不行)。
- HashMap 是非 synchronized,而 HashTable 是 synchronized,这意味着 HashTable 是线程安全的,多个线程可以共享一个 HashTable;而如果没有正确的同步的话,多个线程是不能共享 HashMap 的。Java 5 提供了 ConcurrentHashMap,它是 HashTable 的替代,比 HashTable 的扩展性更好。
- 另一个区别是 HashMap 的迭代器 (Iterator) 是 fail-fast 迭代器,而 HashTable 的 enumerator 迭代器不是 fail-fast 的。所以当有其它线程改变了 HashMap 的结构(增加或者移除元素),将会抛出 ConcurrentModificationException,但迭代器本身的 remove() 方法移除元素则不会抛出 ConcurrentModificationException 异常。但这并不是一个一定发生的行为,要看 JVM。这条同样也是 Enumeration 和 Iterator 的区别。
- 由于 HashTable 是线程安全的也是 synchronized,所以在单线程环境下它比 HashMap 要慢。如果你不需要同步,只需要单一线程,那么使用 HashMap 性能要好过 HashTable。
- HashMap 不能保证随着时间的推移 Map 中的元素次序是不变的。
六. 集合工具类
Stack 类
stack是vector的子类,继承结构和vector完全相同,但是stack中自定义的方法中最常使用的还是push和pop以及peek
Queue 接口
queue接口继承自collection接口,队列是队尾入队,队头出队(左边为头,右边是尾)。队列的实现可以用LinkedList类。
主要的方法如下:
入队:add(越界会抛异常)、offer
出队:remove(队空会抛异常)、poll
查看队首元素:element(队空会抛异常)、peek
Deque 接口
双端队列接口,该接口是Queue的子接口,主要方法有
方法 | 描述 |
---|---|
void addFirst(E e) | 左边插入(队满会报异常) |
boolean offerFirst(E e) | 左边插入 |
void addLast(E e) | 右边插入(队空会报异常) |
boolean offerLast(E e) | 右边插入 |
E removeFirst() | 左边删除(队空会报异常) |
E pollFirst() | 左边删除 |
E removeLast() | 右边删除(队空会报异常) |
E pollLast() | 右边删除 |
E getFirst() | 返回左边第一个元素(队空报异常) |
E peekFirst() | 返回左边第一个元素 |
E getLast() | 返回右边第一个元素(队空报异常) |
E peekLast() | 返回右边第一个元素 |
PriorityQueue 类
继承结构
PriorityQueue是一种通过数组实现的,并拥有优先级的队列。是一种无界的,线程不安全的队列。将最小的元素放在队首,最大的元素放在队尾,其比较是通过添加元素实现Comparable实现的,也可以在构造优先队列是传入Comparator对象。因此PriorityQueue存储的元素要求必须是可比较的对象, 如果不是就必须明确指定比较器
Properties 类
存储方式也是key-value的格式,但是其保存的内容只能是String,是hashTable类的子类。
主要方法:
方法 | 说明 |
---|---|
setProperties(String key,String value) | 设置属性 |
getProperties(String key) | 获取属性 |
store(OutputStream os,String comment) | 将properties输出,比如写入到文件中 |
load(InputStream inStream) | 读入properties |
Collections 类
常用方法
方法 | 说明 |
---|---|
sort(Collection) | 对已知集合进行排序 |
shuffle(Collection) | 队集合进行随机排序 |
binarySearch(List list, T key) | 查找指定元素的位置 |
reverse() | 翻转集合中的元素 |