Collection,Set,List,Queue
Collection 是List,Set和Queue的父接口。该接口里面定义的方法既可以操作List,Set,Queue集合.由于Collection 是 List,Set,Queue的父接口,
方法 | 解释 |
---|---|
boolean add(Object obj) | 添加成功 true |
boolean addAll(Collection v) | 将集合c添加到指定的集合,true成功 |
void clear() | 清除集合里面的所有元素,长度变为0 |
boolean contains(Object obj) | 集合里面是否包含指定元素 |
boolean containsAll(Collection c) | 集合里面是否包含集合集合c里面的所有元素 |
boolean isEmpty() | 集合是否为null,当集合长度为0时返回true |
Iterator iterator() | 返回一个Iterator对象,用于遍历集合中的元素 |
boolean remove(Object obj) | 删除集合中指定元素obj 当集合中包含多个obj只能删除第一个,成功返回ture |
boolean removeAll(Coolection c) | 从集合中删除指定中里不包含c的元素,如果该操作改变了集合(相当于取指定集合和c的交集),返回true |
int size() | 返回集合中元素的个数 |
Object[] toArray() | j将发放转换为一个数组集合 |
Set
Set集合它类型于一个罐子,程可以将多个对象“丢进”Set集合里面。
- Set集合是无序的,不能记住添加顺序,当取出元素时,是无序的
- Set集合不允许包含重复的元素,Set集合里面可以包含null元素,但是只能有一个null
- Set集合与Collection 基本相同,没有任何额外的方法
HashSet
HashSet是Set接口的实现类,HashSet 是按Hash算法来存储集合中的元素,拥有很好的存取,和查询性能。
@Test
public void test01(){
Set<String> set = new HashSet<>();
set.add("AAAA");
set.add("BBBB");
set.add("CCC");
set.add("DDD");
//可以看到set 输出是无序的
System.out.println(set);
System.out.println("移除AAAA:"+set.remove("AAAA"));
System.out.println(set);
}
什么是Hash:
LinkHashSet
LinkHashSet 是HashSet的子类,LinkHashSet是根据hashCode值来决定元素存储的位置,但它同时同链表维护元素的位置,当元素取出元素时,和插入位置相同。
LinkHashSet 性能略微低于HashSet, 因为它用使用了链表维护元素的顺序
@Test
public void test01(){
Set<String> set = new LinkedHashSet<>();
set.add("AAA");
set.add("BBB");
set.add("CCC");
set.add("DDD");
System.out.println(set);
}
TreeSet
ThreeSet是SortSet 接口的实现类,ThreeSet 可以保证元素处于排序状态。当你添加元素元素后ThreeSet会默认使用自然排序法,将元素排序。ThreeSet 采用的红黑树的数据结构来存储集合元素。
方法 | 解释 |
---|---|
Comparator comparator() | 如果ThreeSet采用了定制排序,则方法返定制排序所用的Comparator,如果采用的是自然排序,返回的是null |
Object first() | 返回第一个元素 |
Object last() | 返回最后一个元素 |
Object lower() | 返回小于指定元素的第一个元素 |
Object higher() | 返回大于指定元素的第一个元素 |
SortSet subSet(Object fromElement,Object toElement) | 指定返回元素的范围,fromElement(包含),toElement(不报喊) |
SortSet headSet(Object toElement) | 返回小于toElement的元素集合 |
SortSet tailSet(Object toElement) | 返回大于或等于toElement的元素集 |
@Test
public void test01(){
TreeSet<String> set = new TreeSet<>();
set.add("22");
set.add("10");
set.add("80");
set.add("-20");
//输出的元素的有序的
System.out.println(set);
//返回22之前的第一个元素
System.out.println("小于的第一个元素:"+treeSet.lower("22"));
System.out.println("大于的第一个元素:"+treeSet.higher("10"));
System.out.println("第一个元素:"+treeSet.first());
System.out.println("最后一个元素:"+treeSet.last());
System.out.println("返回小于指定元素的集:"+treeSet.headSet("22"));
}
List
List作为Collection 的子接口,当然可以使用Collection接口里面的所有方法。List集合是有序的,可以重复的,集合中每个元素都有对应的顺序索引。索引是从0开始的。
方法 | 解释 |
---|---|
void add(int index,Object obj) | 将obj元素插入到List集合的index处 |
boolean addAll(int index,Collection c) | 将集合所包含的所有元素都插入到List集合index处 |
Object get(int index) | 返回index索引的位置 |
int indexOf(Object 0) | 返回对象0在List集合中第一次出现的位置 |
int lastIndexOf(Object o) | 反会对象o在List最后一次出现的位置 |
Object remove(int index) | 删除并返回index索引处的元素 |
Object set(int index,Objext obj) | 将index索引的元素替换成obj,返回被替换的旧元素 |
List subList(int indexfromIndex,int toIndex) | 返回索引fromIndex(包含)到toIndex(不包含)处所有集和组成的子元素([fromIndex,toIndex) 区间) |
@Test
public void listTest(){
List<String> books = new ArrayList<>();
//向books集合中添加3个元素
books.add("111");
books.add("222");
books.add("333");
books.add("444");
System.out.println(books);
//向第二位置添加元素,后面的元素都向后移动
books.add(1,"555");
for(String str:books){
System.out.print(str+"\t");
}
//移除第二个元素
System.out.println("移除的元素为:"+books.remove(1));
System.out.print("移除后的元素为:");
for(String str:books){
System.out.print(str+"\t");
}
System.out.println();
System.out.println("将索引为0的位置的元素:"+books.set(0, "aaa")+"修改为:"+books.get(0));
//获取索引为1,2的集合,subList的区间为:[1,3)
List<String> subList = books.subList(1, 3);
System.out.println(subList);
}
下面两个方法是Java8
方法 | 解释 |
---|---|
void replaceAll() | 根据operator指定的计算规则重新设置Lsit集合所有元素 |
void sort(Comparator c) | 根据Comparator参数对List集合排序 |
Arrays.asList
ArrayList 是一个固定长度的List集合程序只能遍历访问该集合中的元素不可增加,删除集合中的元素。
List<String> list = Arrays.asList("AAA","BBB","CCC");
ArrayList 和 Vectory
ArrayList和Vectory作为List接口的实现类,底层是通过数组实现的,数组是一种效率最高的存储和随机访问对象引用序列的方式,数组就是一个简单的线性序列,但是数组有一个致命的缺点,数组对象的大小被固定,期生命周期不可变。每次ArrayList扩容时,都会将原来的数据对象拷贝到新的容器里面。因此ArrayList的效率将会比数组低很多。
jdk8 ArrayList 的grow方法
/**
* Increases the capacity to ensure that it can hold at least the
* number of elements specified by the minimum capacity argument.
*
* @param minCapacity the desired minimum capacity
*/
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
//当ArrayList扩容时,是带符号右移动一位
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
}
- ArrayList 每次扩容并不是原来的1.5倍
上面源码可以看到 int newCapacity = oldCapacity + (oldCapacity >> 1);
oldCapacity + oldCapacity带符号向右移动一位
10 的二进制 1010 当第一次移动后二进制变为: 1010 + 0101 结果: 15,当第二次扩容时: 1111 + 0111 结果:22 ,当第三次移动:0001 1010 + 0000 1101 = 37。
所以说并不是的1.5倍。
ArratList 和Vector 的区别
ArrayList 是线程不安全的,主要体现在多个线程对同一个ArrayList添加元素,就会出现问题。
体现文章:https://blog.csdn.net/zx6571269/article/details/79960415
Vector 是线程安全的,性能比ArrayList低,但是在实际开不会使用Vectory,而是使用Coollection的工具类来包装将ArrayList转换为线程安全的。
Queue 接口
Queue是Colletion的子接口 用于模拟队列这种数据集合,队列通常是指“先进先出”,新插入的元素在队列尾部,队列不允许随机访问。
方法 | 解释 |
---|---|
void add(Object obj) | 将指定的元素加入此队列的尾部 |
Object element() | 获取队列又不元素,但是不删除该元素 |
boolean offer(Object obj) | 将指定元素加入到此队列的尾部,当使用有容量限制的,队列这个方法比add好 |
Object peek() | 获取队列头部的元素,但是不能删除该元素,如果队列为null返回null |
Object poll() | 获取头部的元素,并删除该元素 |
Object remove() | 获取队列头部的元素并删除该元素 |
PriorityQueue
PriorityQueue是Queue的实现类,PriorityQueue保存队列的顺序并不是按加入队列的顺序,而是根据队列元素的大小重新排序。
public static void main(String[] args) {
PriorityQueue<String> priorityQueue = new PriorityQueue<>();
priorityQueue.add("2");
priorityQueue.add("5");
priorityQueue.add("-5");
priorityQueue.add("1");
for (String str : priorityQueue) {
System.out.print(str + "\t");
}
System.out.println();
System.out.println("首部元素为:" + priorityQueue.peek());
}
可以看到元素是按重小到大的顺从。
Deque接口
Deque接口是queue的子接口,它代表一个双端队列。
方法 | 解释 |
---|---|
void addFirst(Object obj) | 将指定元素插入该双端队列的开头 |
void addLast(Objcet obj) | 将该元素插入到双端队列的末尾 |
Iterator descendingIterator() | 返回该双端队列对应的迭代器,以逆向顺序来迭代队列中的元素 |
Object getFirst() | 获取但不能删除双端队列的第一个元素 |
Object getLast() | 获取但不能删除双端队列的最后一个元素 |
Object peekFrist() | 获取但不删除双端队列的第一个元素 |
Object peekLast() | 获取但不删除双端队列的最后一个 |
Object pollFirst() | 获取并删除双端队列的第一个元素 |
Object pollLast() | 获取并删除双端队列的最后一个元素 |
Object pop() | 相当于remove First |
void push(Object obj) | 相当于addFirst(obj) |
Object removeFirst | 移除双端队列的第一个元素 |
Object removeLast() | 获取并删除该双端队列的一个元素 |
boolean removeFirstOccurrence(Object obj) | 删除双端队列的第一次出现的元素obj |
boolean removeLastOccurrence(Object obj) | 删除双端队列最后一次出现的元素 |
ArrayDeque
ArrayDeque是Deque接口的实现类,ArrayDeque和ArrayList两个集合类的实现相似,他们的底部都是采用动态的Object数组。
- ArrayDeque模拟statck的使用
public static void main(String[] args) {
ArrayDeque<String> stack = new ArrayDeque<>();
//将元素依次进行push入栈
stack.push("aaaa");
stack.push("bbbb");
stack.push("cccc");
stack.push("dddd");
//打印栈里面的元素
System.out.println(stack);
//访问栈顶元素
System.out.println("访问栈顶元素"+stack.peek());
System.out.println();
//stack 进行出栈操作,栈顶出栈
System.out.println(stack.pop());
//打印出栈后的数据
System.out.println(stack);
Iterator<String> iterator = stack.descendingIterator();
//以逆向顺序来迭代队列中的元素
while (iterator.hasNext()) {
System.out.print(iterator.next()+"\t");
}
}
在需要使用到”栈”这种数据结构时,使用ArrayDeque,不要使用stack,stack比较古老了,性能较差
- ArrayDeque 模拟队列的使用
public static void main(String[] args) {
ArrayDeque<String> queue = new ArrayDeque<>();
queue.offer("AAAA");
queue.offer("BBBB");
queue.offer("CCCC");
queue.offer("DDDD");
//打印队列李里面的元素
System.out.println(queue);
//打印队列头部的元素
System.out.println("队列头部的元素"+queue.peek());
System.out.println("出队操作:"+queue.poll());
System.out.println(queue);
}
LinkList
LinkList实现List接口和Deque接口。
- LinkList 可以根据索引来访问集合中的元素,因为它实现了List接口
- LisnkList 还可以当做双端队列来使用,因为它实现了Deque接口,当然它可以当做”栈”或者”队列”来使用
Collection 工具类
Collections.synchronizedXXX 同步控制
在Java中在集合框架的实现类:HashSet,ArratList,ArrayDeque,LinkList,HashMap,ThreeMap都是线程不安全的,该方法可以将指定集合包装成为线程同步的集合,可以解决多线程并发访问集合时出现的线程安全问题。
Collection 排序
方法 | 解释 |
---|---|
void reverse(List lsit) | 反转指定List集合中的元素顺序 |
void shuffle(List list) | 对List集合进行随机排序 |
void sort(List list) | 对List集合进行自然顺序排序(升序) |
void swap(List list,int i,int j) | list集合中交换i和j的位置 |
void rotate(List list,int distance) | distance 为正数时,将list集合的后distance个元素移动到前面来,当distance为负数时,将前distance个元素移动都后面,不会改变list的长度 |
查找、替换
方法 | 解释 |
---|---|
int binarySearch(List list,Object key) | 使用二分查找,获取指定对象在List集合索引位置,返回的索引位置(该方法必须保证List集合中的元素是有序的) |
int frequency(Collection c,Object obj) | 返回指定集合中指定元素出现的次数 |
总结:
当遍历集合元素时:
- 对于List和vector采用随机访问方法来遍历(for() foreach)来遍历,这样性能更好。
- 对于LinkList来说使用Iterator遍历性更好
如果要经常执行插入,删除操作改变List集合大小,可以使用LinkList集合,因为ArrayList,Vectory集合可能需要经常分配内部数组的大小,性能比LinkList低。
当有多个线程要用时访问List集合中的元素时,可以使用Collection将集合包装成线程安全的集合