[Java基础]3. Java集合
文章目录
Java集合类是一种特别有用的工具类,可用于存储数量不等的对象,并可以实现常用的数据结构,如栈、队列等。除此之外,Java集合还可用于保存具有映射关系的关联数组。Java集合大致可分为List、Set、Queue和Map四种体系,其中List代表有序、重复的集合;Set代表无序、不可重复的集合;而Map则代表具有映射关系的集合,Java5又增加了Queue体系集合,代表一种队列集合实现。
一、Java集合概述
为了保存数量不确定的数据,以及保存具有映射关系的数据(也被称为关联数组),Java提供了集合类。集合类主要负责保存、盛装其他数据,因此集合类也被称为容器类,所有的集合类都位于java.util
包下。
集合类和数组不一样,数组元素既可以是基本类型的值,也可以是对象(实际上保存的是对象的引用变量);而集合里只能保存对象(实际上只是保存对象的引用变量,但通常习惯上认为集合里保存的是对象)。
Java的集合类主要由两个接口派生而出:Collection
和Map
, Collection和Map是Java集合框架的根接口,这两个接口又包含了一些子接口或实现类。如下所示是 Java集合简单结构图
二、List集合
java.util.List
接口继承自Collection
接口,在List集合元素可重复、元素有序。所有的元素是以一种线性方式进行存储的,在程序中可以通过索引来访问集合中的指定元素(从0开始),而且元素的存入顺序和取出顺序一致。
List作为Collection集合的子接口,不但继承了Collection接口中的全部方法,还有一些根据元素索引来操作集合的特有方法:
public void add(int index, E element)
: 将指定的元素,添加到该集合中的指定位置上。public E get(int index)
:返回集合中指定位置的元素。public E remove(int index)
: 移除列表中指定位置的元素, 返回的是被移除的元素。public E set(int index, E element)
:用指定元素替换集合中指定位置的元素,返回值的更新前的元素。
List的子类
ArrayList
集合
java.util.ArrayList
集合数据存储的结构是数组结构。元素增删慢,查找快,由于日常开发中使用最多的功能为查询数据、遍历数据,所以ArrayList
是最常用的集合。
LinkedList集合
java.util.LinkedList
集合数据存储的结构是双向链表结构。元素增删快,查找慢的集合。
LinkedList提供了大量首尾操作的方法(了解即可):
public void addFirst(E e)
:将指定元素插入此列表的开头。
public void addLast(E e)
:将指定元素添加到此列表的结尾。
public E getFirst()
:返回此列表的第一个元素。
public E getLast()
:返回此列表的最后一个元素。
public E removeFirst()
:移除并返回此列表的第一个元素。
public E removeLast()
:移除并返回此列表的最后一个元素。
public E pop()
:从此列表所表示的堆栈处弹出一个元素。
public void push(E e)
:将元素推入此列表所表示的堆栈。
public boolean isEmpty()
:如果列表不包含元素,则返回true。
LinkedList是List的子类,List中的方法LinkedList都是可以使用,在开发时,LinkedList集合也可以作为堆栈,队列的结构使用。
public class LinkedListDemo {
public static void main(String[] args) {
LinkedList<String> link = new LinkedList<String>();
//添加元素
link.addFirst("a");
link.addFirst("b");
link.addFirst("c");
System.out.println(link);
// 获取元素
System.out.println(link.getFirst());
System.out.println(link.getLast());
// 删除元素
System.out.println(link.removeFirst());
System.out.println(link.removeLast());
while (!link.isEmpty()) { //判断集合是否为空
System.out.println(link.pop()); //弹出集合中的栈顶元素
}
System.out.println(link);
}
}
List方法 | 返回值 | 说明 |
---|---|---|
add(E e) | boolean | 向列表的尾部添加指定的元素。 |
add(int index, E element) | void | 在列表的指定位置插入指定元素。 |
addAll(Collection c) | boolean | 添加指定 collection 中的所有元素到此列表的结尾,顺序是指定 collection 的迭代器返回这些元素的顺序。 |
addAll(int index, Collection c) | boolean | 将指定 collection 中的所有元素都插入到列表中的指定位置。 |
clear() | void | 从列表中移除所有元素。 |
contains(Object o) | boolean | 如果列表包含指定的元素,则返回 true。 |
containsAll(Collectionc) | boolean | 如果列表包含指定 collection 的所有元素,则返回 true。 |
equals(Object o) | boolean | 比较指定的对象与列表是否相等。 |
get(int index) | E | 返回列表中指定位置的元素。 |
hashCode() | int | 返回列表的哈希码值。 |
indexOf(Object o) | int | 返回此列表中第一次出现的指定元素的索引;如果此列表不包含该元素,则返回-1。 |
isEmpty() | boolean | 如果列表不包含元素,则返回 true。 |
iterator() | Iterator | 返回按适当顺序在列表的元素上进行迭代的迭代器。 |
lastIndexOf(Object o) | int | 返回此列表中最后出现的指定元素的索引;如果列表不包含此元素,则返回-1。 |
listIterator() | ListIterator | 返回此列表元素的列表迭代器(按适当顺序)。 |
listIterator(int index) | ListIterator | 返回列表中元素的列表迭代器(按适当顺序),从列表的指定位置开始。 |
remove(int index) | E | 移除列表中指定位置的元素。 |
remove(Object o) | boolean | 从此列表中移除第一次出现的指定元素(如果存在)。 |
removeAll(Collection c) | boolean | 从列表中移除指定 collection 中包含的其所有元素。 |
retainAll(Collection c) | boolean | 仅在列表中保留指定 collection 中所包含的元素。 |
set(int index, E element) | E | 用指定元素替换列表中指定位置的元素。 |
size() | int | 返回列表中的元素数。 |
subList(int fromIndex, int toIndex) | List | 返回列表中指定的 fromIndex(包括 )和 toIndex(不包括)之间的部分视图。 |
toArray() | Object[] | 返回按适当顺序包含列表中的所有元素的数组(从第一个元素到最后一个元素)。 |
toArray(T[] a) | T[] | 返回按适当顺序(从第一个元素到最后一个元素)包含列表中所有元素的数组;返回数组的运行时类型是指定数组的运行时类型。 |
示例代码(以ArrayList为例):
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class ListDemo {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
// 添加元素
list.add("A");
list.add("B");
list.add("C");
list.add("D");
list.add("E");
list.add("A");//允许元素重复
list.add("F");
list.add("G");
list.add(null);//允许元素为null
list.add(null);
// 移除
list.remove(1);// 通过索引移除
list.remove("D");// 通过对象移除
List<String> listRemove = new ArrayList<>();
listRemove.add("E");
listRemove.add("F");
list.removeAll(listRemove);// 移除多个
// 输出list
System.out.println(list);
//遍历
System.out.println("for循环遍历");
for (int i = 0; i < list.size(); i++) {
System.out.print(list.get(i) + "\t"); // 获取list中某个元素 list.get(index)
}
System.out.println("\nforeach 循环:");
for (String string : list) {
System.out.print(string + "\t");
}
// Iterator迭代器
System.out.println("\nIterator 迭代器 while 遍历:");
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) { // iterator.hasNext()判断是否有下一个元素
System.out.print(iterator.next() + "\t");// iterator.next()获取下一个元素
}
System.out.println("\nIterator 迭代器 for 遍历:");
for (Iterator<String> iterator2 = list.iterator(); iterator2.hasNext();) {
String string = iterator2.next();
System.out.print(string + "\t");
System.out.println("-------------------------");
System.out.println("A元素第一次出现的位置:" + list.indexOf("A"));
System.out.println("A元素最后一次出现的位置:" + list.lastIndexOf("A"));
System.out.println("List集合中是否存在元素:" + list.contains("A"));
// 替换元素
list.set(1, "D");
System.out.println(list);
//返回列表中[fromIndex,toIndex)的部分视图
List<String> sList = list.subList(1, 2);
System.out.println(sList);
System.out.println("List集合否为空:" + list.isEmpty());
list.clear();// 清空集合
System.out.println("List集合否为空:" + list.isEmpty());
}
}
三、Set集合
java.util.Set
接口继承自Collection
接口,它与Collection
接口中的方法基本一致,Set
接口中元素无序且不重复,刚好全与list相反
如果试图把两个相同的元素加入同一个Set集合中,则添加操作失败,add()方法返回 false,且新元素不会被加入。
Set集合方法 | 返回值 | 说明 |
---|---|---|
add(E e) | boolean | 如果 set 中尚未存在指定的元素,则添加此元素。 |
addAll(Collection c) | boolean | 如果 set 中没有指定 collection 中的所有元素,则将其添加到此 set 中。 |
clear() | void | 移除此 set 中的所有元素。 |
contains(Object o) | boolean | 如果 set 包含指定的元素,则返回 true。 |
containsAll(Collection c) | boolean | 如果此 set 包含指定 collection 的所有元素,则返回 true。 |
equals(Object o) | boolean | 比较指定对象与此 set 的相等性。 |
hashCode() | int | 返回 set 的哈希码值。 |
isEmpty() | boolean | 如果 set 不包含元素,则返回 true。 |
iterator() | int | 返回在此 set 中的元素上进行迭代的迭代器。 |
remove(Object o) | boolean | 如果 set 中存在指定的元素,则将其移除。 |
removeAll(Collection c) | boolean | 移除 set 中那些包含在指定 collection 中的元素。 |
retainAll(Collection c) | boolean | 仅保留 set 中那些包含在指定 collection 中的元素。 |
size() | int | 返回 set 中的元素数(其容量)。 |
toArray() | Object[] | 返回一个包含 set 中所有元素的数组。 |
toArray(T[] a) | T[] | 返回一个包含此 set 中所有元素的数组;返回数组的运行时类型是指定数组的类型。 |
(一)HashSet类
java.util.HashSet
是Set
接口的一个实现类,它所存储的元素是不可重复、无序(即存取顺序不一致)。java.util.HashSet
底层的实现其实是一个java.util.HashMap
支持。
HashSet
类具有以下特点:
- 不能保证元素的排列顺序,顺序可能与添加顺序不同,顺序也有可能发生变化。
- HashSet不是同步的(不是线程安全的),如果多个线程同时访问一个HashSet,假设有两个或者两个以上线程同时修改了 HashSet集合时,则必须通过代码来保证其同步。
- 集合元素值可以是null,但只能放入一个null。
HashSet
是根据对象的哈希值来确定元素在集合中的存储位置,因此具有良好的存取和查找性能。保证元素唯一性的方式依赖于:hashCode
与equals
方法。
HashSet判断元素不相等的依据:对象的equals()
比较返回false
,且hashCode
值不相等。
当向HashSet集合中存入一个元素时, HashSet会调用该对象的hashCode()方法来得到该对象的hashCode值,然后根据该hashCode值决定该对象在HashSet中的存储位置。如果有两个元素通过 equals方法比较返回true,但它们的hashCode()方法返回值不相等, HashSet将会把它们存储在不同的位置,依然可以添加成功。
给HashSet中存放自定义类型元素时,需要重写对象中的hashCode和equals方法,建立自己的比较方式,才能保证HashSet集合中的对象唯一。
public class Student {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
Student student = (Student) o;
return age == student.age &&
Objects.equals(name, student.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
hashset示例
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
public class HashSetDemo {
public static void main(String[] args) {
HashSet<String> set = new HashSet<>();
// 添加元素
set.add("B");
set.add("A");
set.add("C");
set.add("A");
set.add("I");
set.add("I");
set.add(null);//可以放入null,但只能放入一个null
// 移除
//set.remove("I");
List<String> list = new ArrayList<>();
list.add("F");
set.removeAll(list);
// 输出set
System.out.println(set.toString());
// 遍历
System.out.println("foreach遍历:");
for (String string : set) {
System.out.print(string + " ");
}
// 迭代器遍历
System.out.println("\nIterator 迭代器 while:");
Iterator<String> iterator = set.iterator();
while (iterator.hasNext()) {
System.out.print(iterator.next() + " ");
}
System.out.println("\nIterator 迭代器 for:");
for (Iterator<String> iterator2 = set.iterator(); iterator2.hasNext();) {
String string = (String) iterator2.next();
System.out.print(string + " ");
}
// 获取元素个数
System.out.println("HashSet的元素格个数:" + set.size());
// HashSet中是否包含某个元素
System.out.println("HashSet中是否包含某个元素:" + set.contains("F"));
//清空set
set.clear();
//
System.out.println("set是否为空"+set.isEmpty());
}
}
(二)LinkedHashSet类
HashSet类还有一个子类 LinkedHashSet
,当遍历 LinkedhashSet集合里的元素时, LinkedHashSet将会按元素的添加顺序来访问集合里的元素。 LinkedHashSet需要维护元素的插入顺序,因此性能略低于 HashSet的性能,但在迭代访问Set里的全部元素时将有很好的性能,因为它以链表来维护内部顺序。
(三)TreeSet类
TreeSet是 SortedSet接口的实现类,正如 SortedSet名字所暗示的, TreeSet可以确保集合元素处于排序状态。与 Set集合相比,TreeSet还提供了如下几个额外的方法。
方法 | 返回值 | 说明 |
---|---|---|
comparator() | Comparator | 返回对此 set 中的元素进行排序的比较器;如果此 set使用其元素的自然顺序,则返回 null。 |
first() | E | 返回此 set 中当前第一个(最低)元素。 |
floor(E e) | E | 返回此 set 中小于等于给定元素的最大元素;如果不存在这样的元素,则返回 null。 |
higher(E e) | E | 返回此 set 中严格大于给定元素的最小元素;如果不存在这样的元素,则返回 null。 |
last() | E | 返回此 set 中当前最后一个(最高)元素。 |
lower(E e) | E | 返回此 set 中严格小于给定元素的最大元素;如果不存在这样的元素,则返回 null。 |
ceiling(E e) | E | 返回此 set 中大于等于给定元素的最小元素;如果不存在这样的元素,则返回 null。 |
headSet(E toElement) | SortedSet | 返回此 set 的部分视图,其元素严格小于 toElement。 |
tailSet(E fromElement) | SortedSet | 返回此 set 的部分视图,其元素大于等于fromElement。 |
subSet(E fromElement, E toElement) | SortedSet | 返回此 set 的部分视图,其元素从 fromElement(包括)到 toElement(不包括)。 |
(四)、各Set实现类的选择
HashSet和TreeSet是Set的两个典型实现,如何选择HashSet和TreeSet?
HashSet的性能总是比TreeSet好(特别是最常用的添加、查询元素等操作),因为TreeSet需要额外的红黑树算法来维护集合元素的次序。只有当需要一个保持排序的Set时,才应该使用TreeSet,否则一般都应该使用HashSet。
LinkedHashSet
对于普通的插入、删除操作,LinkedHashSet比HashSet要略微慢一点,这是由维护链表所带来的额外开销造成的,但由于有了链表,遍历LinkedHashSet会更快。
Set的实现类HashSet、TreeSet都是线程不安全的。如果有多个线程同时访问一个Set集合,并且有超过一个线程修改了该Set集合,则必须手动保证该Set集合的同步性。通常可以通过Collections工具类的synchronizedSortedSet
方法来“包装”该Set集合。
Set<String> set= Collections.synchronizedSet(new HashSet<String>());
四、Queue队列
方法 | 返回值 | 说明 |
---|---|---|
add(E e) | boolean | 将指定的元素插入此队列(如果立即可行且不会违反容量限制),在成功时返回 true, 如果当前没有可用的空间,则抛出IllegalStateException。 |
element() | E | 获取,但是不移除此队列的头。 |
offer(E e) | boolean | 将指定的元素插入此队列(如果立即可行且不会违反容量限制) |
peek() | E | 获取但不移除此队列的头;如果此队列为空,则返回 null。 |
poll() | E | 获取并移除此队列的头,如果此队列为空,则返回 null。 |
remove() | E | 获取并移除此队列的头。 |
import java.util.LinkedList;
import java.util.Queue;
public class QueueDemo {
public static void main(String[] args) {
// add()和remove()方法在失败的时候会抛出异常(不推荐)
Queue<String> queue = new LinkedList<String>();
// 添加元素
queue.offer("同学A");
queue.offer("同学B");
queue.offer("同学C");
// 遍历队列
System.out.println("‐‐‐‐遍历队列‐‐‐‐");
for (String q : queue) {
System.out.print(q + "\t");
}
System.out.println();
// 返回第一个元素,并在队列中删除
System.out.println("‐‐‐‐‐‐poll‐‐‐‐‐‐");
System.out.println("poll " + queue.poll());
System.out.println(queue);
// 返回第一个元素
System.out.println("‐‐‐‐‐‐element‐‐‐‐‐‐");
System.out.println("element " + queue.element());
System.out.println(queue);
// 返回第一个元素
System.out.println("‐‐‐‐‐‐peek‐‐‐‐‐‐");
System.out.println("peek " + queue.peek());
System.out.println(queue);
}
}
五、Map集合
Map接口中键和值一一映射. 可以通过键来获取值。
- 给定一个键和一个值,你可以将该值存储在一个Map对象. 之后,你可以通过键来访问对应的值。
- 当访问的值不存在的时候,方法就会抛出一个
NoSuchElementException
异常. - 当对象的类型和Map里元素类型不兼容的时候,就会抛出一个
ClassCastException
异常。 - 当在不允许使用Null对象的Map中使用Null对象,会抛出一个
NullPointerException
异常。 - 当尝试修改一个只读的Map时,会抛出一个
UnsupportedOperationException
异常。
方法 | 返回值 | 说明 |
---|---|---|
clear() | void | 从此映射中移除所有映射关系(可选操作)。 |
containsKey(Object key) | boolean | 如果此映射包含指定键的映射关系,则返回 true。 |
containsValue(Object value) | boolean | 如果此映射将一个或多个键映射到指定值,则返回true。 |
entrySet() | Set<Map.Entry> | 返回此映射中包含的映射关系的 Set 视图。 |
equals(Object o) | boolean | 比较指定的对象与此映射是否相等。 |
get(Object key) | V | 返回指定键所映射的值;如果此映射不包含该键的映射关系,则返回 null。 |
hashCode() | int | 返回此映射的哈希码值。 |
isEmpty() | boolean | 如果此映射未包含键-值映射关系,则返回 true。 |
keySet() | Set | 返回此映射中包含的键的 Set 视图。 |
put(K key, V value) | V | 将指定的值与此映射中的指定键关联 |
putAll(Map m) | void | 从指定映射中将所有映射关系复制到此映射中 |
remove(Object key) | V | 如果存在一个键的映射关系,则将其从此映射中移除 |
size() | int | 返回此映射中的键值映射关系数。 |
values() | Collection | 返回此映射中包含的值的 Collection 视图。 |
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class HashMapAndHashTable {
public static void main(String[] args) {
// 如果是基本数据类型,声明的map的时候使用包装类
Map<Integer, String> map = new HashMap<>();
// 添加数据 put当key不存在时,添加key‐value
map.put(1, "str1");
map.put(2, "str2");
map.put(3, "str3");
map.put(4, "str4");
map.put(5, "str5");
// put 当key存在时,修改key对应的value
map.put(5, "111111");
map.put(6, null);
map.put(7, null);
// 移除 remove(key)
map.remove(7);
// 判断是否存在key
System.out.println("是否存在key:5===》" + map.containsKey(5));
// 判断是否存在value
System.out.println("是否存在Value:str4====>" + map.containsValue("str4"
// 清空map
// map.clear();
System.out.println("map是否为空:" + map.isEmpty());
// 输出
System.out.println(map);
// 遍历
Set<Integer> keysSet = map.keySet();
Iterator<Integer> iterator = keysSet.iterator();
while (iterator.hasNext()) {
Integer intKey = iterator.next();
System.out.println("key:" + intKey + "‐‐‐‐>Value:" + map.get(intKey));
}
System.out.println("‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐");
for (Iterator<Integer> iterator2 = keysSet.iterator(); iterator2.hasNext
int intKey = iterator2.next();
System.out.println("key:" + intKey + "‐‐‐‐>Value:" + map.get(intKey));
}
System.out.println("‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐");
for (int intKey : keysSet) {
System.out.println("key:" + intKey + "‐‐‐‐>Value:" + map.get(intKey));
}
}
}
TreeMap类
与 TreeSet类似的是,TreeMap中也提供了一系列根据key顺序访问key-value对的方法:
方法 | 返回值 | 说明 |
---|---|---|
firstEntry() | Map.Entry | 返回一个与此映射中的最小键关联的键值映射关系; 如果映射为空,则返回 null。 |
firstKey() | K | 返回此映射中当前第一个(最低)键。 |
lastEntry() | Map.Entry | 返回与此映射中的最大键关联的键值映射关系; 如果映射为空,则返回 null。 |
lastKey() | K | 返回映射中当前最后一个(最高)键。 |
higherEntry(K key) | Map.Entry | 返回一个键值映射关系,它与严格大于给定键的最小键关联; 如果不存在这样的键,则返回 null。 |
higherKey(K key) | K | 返回严格大于给定键的最小键;如果不存在这样的键,则返回 null。 |
lowerEntry(K key) | Map.Entry | 返回一个键值映射关系,它与严格小于给定键的最大键关联; 如果不存在这样的键,则返回 null。 |
lowerKey(K key) | K | 返回严格小于给定键的最大键; 如果不存在这样的键,则返回 null。 |
headMap(K toKey) | SortedMap | 返回此映射的部分视图,其键值严格小于 toKey。 |
subMap(K fromKey, K toKey) | SortedMap | 返回此映射的部分视图,其键值的范围[ fromKey , toKey ) |
tailMap(K fromKey) | SortedMap | 返回此映射的部分视图,其键大于等于 fromKey。 |
六、Java集合工具类:Collections
Java提供了一个操作Set、List和Map等集合的工具类:Collections
,该工具类里提供了大量方法对集合元素进行排序、查询和修改等操作,还提供了对集合对象实现同步控制等方法。
public static <T> boolean addAll(Collection<T> c, T... elements)
: 往集合中添加一些元素。
public static void shuffle(List<?> list) 打乱顺序:打乱集合顺序。
public static void sort(List list):将集合中元素按照默认规则排序。
public static void sort(List list,Comparator<? super T> ):将集合中元素按照指定规则排序。
(一)排序操作
方法 | 修饰符 | 返回值 | 说明 |
---|---|---|---|
reverse(List list) | static | void | 反转指定列表中元素的顺序。 |
shuffle(List list) | static | void | 打乱集合顺序 |
sort(List list) | static | void | 将集合中元素按照默认规则排序 |
sort(List list, Comparator c) | static | void | 将集合中元素按照指定规则排序 |
swap(List list, int i, int j) | static | void | 在指定列表的指定位置处交换元素。 |
rotate(List list, int distance) | static | void | 根据指定的距离轮换指定列表中的元素。 |
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class SortDemo {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
原来添加写法
//list.add(1);
//list.add(2);
//list.add(3);
//list.add(4);
//list.add(5);
//list.add(6);
//list.add(7);
//list.add(8);
//list.add(9);
//采用工具类 完成 往集合中添加元素
Collections.addAll(list, 1, 2, 3,4, 5, 6, 7, 8, 9);
System.out.println("list‐‐>"+list);
System.out.println("‐‐‐‐倒序 reverse‐‐‐");
Collections.reverse(list);//倒序 9,8,7,6,5,4,3,2,1,
System.out.println("list‐‐>"+list);
System.out.println("‐‐‐随机顺序 shuffle‐‐‐");
Collections.shuffle(list);//每次执行后的顺序都是随机排列的
System.out.println("list‐‐>"+list);
System.out.println("‐‐‐自然顺序排序 sort‐‐‐");
Collections.sort(list);//自然顺序排序
System.out.println("list‐‐>"+list);
System.out.println("‐‐‐自定义排序 sort‐‐‐");
Collections.sort(list,new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
//从大到小
return o2‐o1;
}
});
System.out.println("list‐‐>"+list);
System.out.println("‐‐‐交换元素 swap‐‐‐");
Collections.swap(list,0,8);
System.out.println("list‐‐>"+list);
System.out.println("‐‐‐自然顺序排序 sort‐‐‐");
Collections.sort(list); //自然顺序排序
System.out.println("list‐‐>"+list);
System.out.println("‐‐‐rotate(2)‐‐‐");
Collections.rotate(list,2);
System.out.println("list‐‐>"+list);
System.out.println("‐‐‐rotate(‐2)‐‐‐");
Collections.rotate(list,‐2);
System.out.println("list‐‐>"+list);
}
}
(二)查找和替换操作
下列方法的修饰符都是static
。
方法 | 返回值 | 说明 |
---|---|---|
binarySearch(List list, T key) | int | 使用二分搜索法搜索指定列表,以获得指定对象。 |
binarySearch(List list, T key,Comparator c) | int | 使用二分搜索法搜索指定列表,以获得指定对象。 |
max(Collection coll) | Object | 根据元素的自然顺序,返回给定 collection 的最大元素。 |
max(Collection coll,Comparator c) | Object | 根据指定比较器产生的顺序,返回给定collection 的最大元素。 |
min(Collection coll) | Object | 根据元素的自然顺序,返回给定 collection 的最小元素。 |
min(Collection coll,Comparator c) | Object | 根据指定比较器产生的顺序,返回给定collection 的最小元素。 |
fill(List list, T obj) | void | 使用指定元素替换指定列表中的所有元素。 |
frequency(Collection c, Object o) | int | 返回指定 collection 中等于指定对象的元素数。 |
indexOfSubList(List source, List target) | int | 返回指定源列表中第一次出现指定目标列表的起始位置; 如果没有出现这样的列表,则返回-1。 |
lastIndexOfSubList(List source, List target) | int | 返回指定源列表中最后一次出现指定目标列表的起始位置; 如果没有出现这样的列表,则返回-1。 |
replaceAll(List list, T oldVal, T newVal) | boolean | 使用另一个值替换列表中出现的所有某一指定值。 |
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class SearchDemo {
public static void main(String[] args)
{
List<Integer> list = new ArrayList<>();
list.add(5);
list.add(‐10);
list.add(3);
list.add(9);
list.add(‐1);
list.add(7);
list.add(0);
System.out.println(list);
System.out.println("‐‐‐‐‐max‐‐‐‐");
System.out.println(Collections.max(list)); // 输出最大元素
System.out.println("‐‐‐‐‐min‐‐‐‐");
System.out.println(Collections.min(list)); // 输出最小元素
System.out.println("‐‐‐‐‐replaceAll‐‐‐‐");
Collections.replaceAll(list , 0 , 1); // 将nums中的0使用1来代替
System.out.println(list);
System.out.println("‐‐‐‐‐frequency‐‐‐‐");
System.out.println(Collections.frequency(list , 5)); // 判断5在List集合中出现的次数
System.out.println("‐‐‐‐‐binarySearch‐‐‐‐");
Collections.sort(list); // 对nums集合排序
System.out.println(list);
//只有排序后的List集合才可用二分法查询元素的索引
System.out.println(Collections.binarySearch(list , 5));
List<Integer> list2 = new ArrayList<>();
list2.add(‐1);
list2.add(1);
System.out.println("‐‐‐‐‐indexOfSubList‐‐‐‐");
System.out.println(Collections.indexOfSubList(list, list2));//查找子列表
System.out.println("‐‐‐-‐lastIndexOfSubList‐‐‐‐");
System.out.println(Collections.lastIndexOfSubList(list , list2));//查找子列表
System.out.println("‐‐‐‐‐fill‐‐‐‐");
Collections.fill(list, 0);//用0填充list
System.out.println(list);
}
}
(三)同步控制
Collections类中提供了多个 synchronized…()方法,这些方法可以将指定集合包装成线程同步(线程安全)的集合,从而可以解决多线程并发访问集合时的线程安全问题。
Java中常用的集合框架中的实现类 ArrayList、Linkedlist、 HashSet、TreeSet、HashMap和TreeMap都是线程不安全的。如果有多个线程访问它们,而且有超过一个的线程试图修改它们,则存在线程安全的问题。 Collections提供了多个类方法可以把它们包装成线程同步的集合。
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class SynchronizedDemo {
public static void main(String[] args) {
List<String> list=Collections.synchronizedList(new ArrayList<String>());
Set<String> set=Collections.synchronizedSet(new HashSet<String>());
Map<Integer, String> map=Collections.synchronizedMap(new HashMap<Integer>());
}
}
七、Comparable和Comparator
(一)Comparable
Comparable是排序接口。若一个类实现了Comparable接口,就意味着该类支持排序。实现了Comparable接口的类的对象的列表或数组可以通过Collections.sort
或Arrays.sort
进行自动排序,无需指定比较器。
Comparable接口只有一个方法compare
,比较此对象与指定对象的顺序,如果该对象小于、等于或大于指定对象,则分别返回负整数、零或正整数。
示例
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
//Comparable 排序接口 是在类的内部实现
public class ListComparable {
public static void main(String[] args) {
List<PersonComparable> persons = new ArrayList<PersonComparable>();
persons.add(new PersonComparable("小A", 35));
persons.add(new PersonComparable("小B", 25));
persons.add(new PersonComparable("小C", 25));
persons.add(new PersonComparable("小D", 12));
persons.add(new PersonComparable("小X", 33));
persons.add(new PersonComparable("小M", 33));
persons.add(new PersonComparable("小E", 33));
//第三步 调用sort 排序
Collections.sort(persons);
//使用迭代器遍历输出列表数据
Iterator<PersonComparable> iterator = persons.iterator();
while (iterator.hasNext()) {
PersonComparable persion = iterator.next();
System.out.println(persion.getName()+"\t"+persion.getAge());
}
}
}
// 第一步 :实现接口Comparable<T>
class PersonComparable implements Comparable<PersonComparable> {
private int age;
private String name;
public PersonComparable() {
}
public PersonComparable(String name, int age) {
this.name = name;
this.age = age;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
/**
* 第二步 实现compareTo方法,o表示和当前对象比较的另外一个对象
*/
@Override
public int compareTo(PersonComparable o) {
// 从小到大 :this‐o
// 从大到小:o‐this
// return this.age ‐ o.age;
//改进比较方法:先根据年龄排序,如果年龄一样,根据姓名排序
if (this.age!=o.age) {
return this.age ‐ o.age;
} else {
return this.name.compareTo(o.name);
}
}
}
(二)Comparator
Comparator是比较接口,我们如果需要控制某个类的次序,而该类本身不支持排序(即没有实现Comparable接口),那么我们就可以建立一个“该类的比较器”来进行排序,这个“比较器”只需要实现Comparator接口即可。也就是说,我们可以通过实现
Comparator来新建一个比较器,然后通过这个比较器对类进行排序。
注意:
- 若一个类要实现Comparator接口:它一定要实现
compare(T o1, T o2)
函数,但可以不实现equals(Object obj)
函数。 int compare(T o1, T o2)
是“比较o1和o2的大小”。返回“负数”,意味着“o1比o2小”;返回“零”,意味着“o1等于o2”;返回“正数”,意味着“o1大于o2”。
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
public class ListComparator {
public static void main(String[] args) {
List<PersonComparator> persons = new ArrayList<PersonComparator>();
persons.add(new PersonComparator("小A", 35));
persons.add(new PersonComparator("小B", 25));
persons.add(new PersonComparator("小C", 25));
persons.add(new PersonComparator("小D", 12));
persons.add(new PersonComparator("小X", 33));
persons.add(new PersonComparator("小M", 33));
persons.add(new PersonComparator("小E", 33));
// 调用sort 排序
Collections.sort(persons, new Comparator<PersonComparator>() {
@Override
public int compare(PersonComparator o1, PersonComparator o2) {
/**
* 从小到大:o1‐o2 从大到小:o2‐o1
*/
//改进比较方法:先根据年龄排序,如果年龄一样,根据姓名排序
if (o1.getAge() != o2.getAge()) {
return o1.getAge() ‐ o2.getAge();
} else {
return o2.getName().compareTo(o1.getName());
}
}
});
//使用迭代器遍历输出列表数据
Iterator<PersonComparator> iterator = persons.iterator();
while (iterator.hasNext()) {
PersonComparator persion = iterator.next();
System.out.println(persion.getName()+"\t"+persion.getAge());
}
}
}
class PersonComparable implements Comparable<PersonComparable> {
private int age;
private String name;
public PersonComparable() {
}
public PersonComparable(String name, int age) {
this.name = name;
this.age = age;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
(三)Comparable和Comparator区别比较
- Comparable是排序接口,若一个类实现了Comparable接口,就意味着“该类支持排序”。Comparator是比较器,我们若需要控制某个类的次序,可以建立一个“该类的比较器”来进行排序。
- 用Comparable简单, 只要实现Comparable 接口的对象直接就成为一个可以比较的对象,但是需要修改源代码。 用Comparator 的好处是不需要修改源代码, 而是另外实现一个比较器, 当某个自定义的对象需要作比较的时候,把比较器和对象一起传递过去就可以比大小了, 并且在Comparator里面用户可以自己实现复杂的可以通用的逻辑,使其可以匹配一些比较简单的对象,那样就可以节省很多重复劳动了。
八、Java集合总结
- List,Set,Map是集合体系中最主要的三个接口。其中list和set是继承自collection接口,Map也属于集合系统但是与collection接口不同。
- list是有序且允许元素重复,允许元素为null,ArrayList、LinkedList和Vector是三个主要的实现类
- Vector、ArrayList都是以类似数组的形式存储在内存中,LinkedList则以链表的形式进行存储。
- Vector线程安全的(同步),ArrayList、LinkedList线程不安全的(不同步)。
- ArrayList、Vector适合查找,不适合指定位置的插入、删除操作;LinkedList适合指定位置插入、删除操作,不适合查找。
- ArrayList在元素填满容器时会自动扩充容器大小的50%,而Vector则是100%,因此ArrayList更节省空间。
- set是无序,不允许元素重复;HashSet和TreeSet是两个实现类
- HashSet 基于HashMap实现,HashSet中的数据是无序的,可以放入null,但只能放入一个null,两者中的值都不能重复,要求放入的对象必须实现HashCode()方法,放入的对象,是以hashcode码作为标识的
- TreeSet 是二差树实现的,Treeset中的数据是自动排好序的,不允许放入null值
- Comparator 和 Comparable 的区别
- Comparator定义在类的外部, 此时我们的类的结构不需要有任何变化,从小到大:o1-o2从大到小:o2-o1
- Comparable定义在类的内部,耦合性较强 从小到大 :this-o 从大到小:o-this
- 线程安全的就是同步的,不安全的就是不同步的;不同步的运行速度要比同步的快。