一、Java集合简述
(1)java集合思维导图
简版:
List , Set, Queue,Map都是接口,前三个继承至collection接口,Map为独立接口。
二、Set集合
- 不包含重复元素;
- Set最多有一个null;
- 元素没有顺序;
- 如果需要访问元素,通过元素本身来访问。
(1)HashSet
- 不保证元素的排列顺序。
- 不同步。
- 元素值可以为null。
- 根据hashCode的值来决定元素存储位置。
- 如果HashSet中两元素equals()返回true,但它们的hashCode()方法返回值不相等,HashSet会把它们存储再不同位置(如果重写equals(),那也要重写hashCode())。
如果equals()返回true,但hashCode返回的值不同时,HashSet会把它们保存在Hash表的不同位置。
如果hashCode返回值相等,但equals()放回值不相同时,会以链式结构保存对象。
例:
package com.company;
import java.util.*;
class A{
public boolean equals(Object object){
return ture;
}
}
class B{
public int hashCode(){
return 1;
}
}
class C{
public boolean equals(Object object){
return ture;
}
public int hashCode(){
return 2;
}
}
public class Test{
public static void main(String[] args) {
var books=new HashSet<>();
books.add(new A());
books.add(new A());
books.add(new B());
books.add(new B());
books.add(new C());
books.add(new C());
System.out.println(books);
}
}
----------------------------------
输出结果:
[B@1, B@2,C@2,A@13c78c0b,A@2cb4c3ab]
(2)LinkedHashSet
- 根据hashCode的值来决定元素存储位置。
- 维护顺序(以链表来维护)。
- 按添加顺序来访问集合里的元素。
(3)TreeSet
- 是SortSet接口的实现类,所以能确保集合处于排序状态(根据元素值大小)。
- 使用红黑树的数据结构来存储元素。
- 支持两种排序方法:自然排序 和 定制排序。
①自然排序
会调用compareTo(Object obj)来比较元素大小(obj1.compareTo(obj2),返回0,相等;返回正整数,obj1>obj2;放回负整数obj1<obj2).
如果希望TreeSet能正常运作,TreeSet只能添加同一种类型的对象。
②定制排序
运用Lambo重写compareTo(o1,o2)的排序方法。
(4)EnumSet
是专门为枚举类设计的集合类,EnumSet中所有元素必须是指定枚举类型的枚举值。
(5)小结:
- HashSet性能总是比TreeSet好,因为TreeSet需要额外的红黑树算法来维护次序。
- 对于普通的插入、删除操作,LinkedHashSet比HashSet要稍微慢点,因为要维护链表;但因为LinkedHashSet有链表,遍历数组会快。
- EnumSet是所有Set中性能最好的,但只能保存同一个枚举类的枚举值。
- HashSet,TreeSet,EnumSet都是线程不安全的。如果有多个线程访问同一个Set,并且有超过一个线程修改了该Set集合,则必须手动保证Set安全,通常使用Collections的synchronizedSortedSet来“包装”。
例:
SortedSet s=Collections.synchronizedSortedSet(new TreeSet(...));
三、List集合
- 有序;
- 可重复;
- 每个元素有对应索引;
- 默认按元素的添加顺序设置元素的索引;
- 通过索引访问元素
List集合常用方法:
public class Test {
public static void main(String[] args) {
List list = new ArrayList();
// 向列表的尾部追加指定的元素
list.add("add");
// 在列表的指定位置插入指定元素
list.add(1,"bdd");
// 把ArrayList追加到list 中的所有元素到此列表的结尾
list.addAll(new ArrayList());
// 从列表中移除所有元素
list.clear();
// 如果列表包含指定的元素,则返回true
list.contains("add");
// 如果列表包含指定 collection 的所有元素,则返回 true
list.containsAll(new ArrayList());
// 比较指定的对象与列表是否相等
list.equals(new ArrayList());
// 返回列表中指定位置的元素
list.get(0);
// 返回列表的哈希码值
list.hashCode();
// 返回列表中首次出现指定元素的索引,如果列表不包含此元素,则返回 -1
list.indexOf("add");
// 返回列表中最后出现指定元素的索引,如果列表不包含此元素,则返回 -1
list.lastIndexOf("add");
// 如果列表不包含元素,则返回 true
list.isEmpty();
// 移除列表中指定位置的元素
list.remove(0);
// 移除列表中出现的首个指定元素
list.remove("add");
// 从列表中移除指定 collection 中包含的所有元素
list.removeAll(new ArrayList());
// 用指定元素替换列表中指定位置的元素
list.set(0, "add");
// 返回列表中的元素数
list.size();
// 返回列表中指定的fromIndex(包括)和toIndex(不包括)之间的部分视图
list.subList(1, 2);
// 返回以正确顺序包含列表中的所有元素的数组
list.toArray();
// 按()中Comparator的Lambda表达式对集合排序
list.sort((o1,o2)->(String)o1.length-(String)o2.length);
//按照operator指定计算规则重新蛇者List集合的所有元素
list.replaceALL(ele->((String)ele).length());
}
}
List不单有iterator()方法,还有listIterator()方法。
listIterator()在iterator()上增加了如下方法:
//返回该迭代器关联集合是否还有上一个元素
boolean hasPrevious():
//返回迭代器上一个元素
Object previous():
//指定位置插入一个元素
void add(Object o):
(1)Arraylist和Vector实现类
Arraylist和Vector能封装一个动态的、一个允许再分配的Object[]数组,所以它们都有一个
容量(Capacity),即用于存储元素的数组的大小。这个容量可随着不断添加新元素而自动增加。
(2)LinkedList实现类
既可以被当成战“栈”使用,也可以当队列使用
(3)小结
- ArrayList、ArrayDeque内部以数组形式保存集合元素;LinkedList内部以链表形式保存。
- ArrayList,Vector随机访问使用get() 来遍历元素;LinkedList则应该采用迭代器(Iterator) 来遍历集合元素。
四、Queue集合
- 先进先出的“容器”。
- 不允许随机访问队列中的元素。
Queue集合常用方法如:
//元素加入尾部。
void add(Object e);
//获取头部元素但不删除。
Object element();
//将指定元素加入队列尾部。
boolean offer(Object e);
//获取队列头部元素,但不删除。若队列为空,则返回null。
Object peek();
//获取队列头部元素,并删除。若队列为空,则返回null。
Object poll();
//获取队列头部元素,并删除。
Object remove();
五、Map集合
Map的Map的主要特点是它存放的元素为key-value对。
- key不允许重发。
- key和value之间存在单向一对一关系。
- 把Map所有key放在一起看,它们就组成一个Set集合;Map中所有value放在一起看,它们非常类似与一个List。
- Map提供一个Entry内部类来封装key-value对,计算Entry存储时则只考虑封装的key。
常用方法如下:
//删除该Map对象中的所有key-value对。
void clear():
//查询Map中是否包含指定的key,如果包含则返回true。
boolean containsKey(Object key):
//查询Map中是否包含一个或多个value,如果包含则返回true。
boolean containsValue(Object value):
//返回map中包含的key-value对所组成的Set集合,每个集合元素都是map.Entry对象
Set entrySet():
//返回指定key所对应的value;如果此map中不包含该key,则返回null。
Object get(Object key):
//查询该map是否为空,如果为空,则返回true。
boolean isEmpty():
//返回该map中所有key组成的set集合
Set keySet():
//添加一个key-value对,如果当前map中已有一个与该key相等的key-value对,则新的key-value对会覆盖原来的key-value对。
Object put(Object key,Object value):
//将指定map中的key-value对复制到本map中
void putAll(Map m):
//删除指定key所对应的key-value对,返回被删除key所关联的value,如果该key不存在,则返回null。
Object remove(Object key):
//删除指定key,value所对应的key-value对,如果从该map中成功地删除该key-value对,该方法返回true,否则返回false。
boolean remove(Object key,Object value):
//返回该map里的key-value对的个数。
int size():
//返回该map里所有value组成的collection。
Map中包括了一个内部类Entry,该类封装了一个key-value对。Entry包含如下三个方法。
collection values():
//返回该Entry里包含的key值
Object getKey():
//返回该Entry里包含的value值。
Object getValue():
//设置该Entry里包含的value值,并返回新设置的value值。
Object setValue(V value):
(1)HashMap和Hashtable实现类
- HashMap的key不允许重复。
- 与HashSet一样不能保证元素顺序。
- 需要和HashSet一样用equals()和hashCode来判断是否相等
- 尽量不要使用可变对象作为HashMap、Hashtable的key。
(2)LinkedHashMap实现类
- 使用双向链表来维护key-value对的顺序,该链表负责维护Map的迭代器,顺序与插入顺序一致。
(3)SortedMap接口与TreeMap实现类
- TreeMap是红黑树数据结构。
- TreeMap存储key-value对(节点)时,需要根据key对节点排序,所以可以保证所有key-value对处于有序状态。
- TreeMap也有两种排序方式。
(4)EnumMap实现类
- 内部以数组形式保存。
- 根据key的自然顺序维护key-value对的顺序。
- 与枚举类一起使用的Map实现。
(5)小结
- TreeMap的ket-value对总是处于有序状态,可通过keySet()取得由key组成的Set,然后用toArray()方法生成key的数组,方便查询。
- HashMap位快速查询设计的;但如果程序总是需要排好序的Map时,则考虑使用TreeMap。
六、操作集合的工具类:Collections
常见排序方法如下:
//反转顺序
void reverse(List list):
//随机排序
void shuffle(List list):对List集合元素进行随机排序
//按升序排序
void sort(List list):
//根据指定Comparator产生的顺序排序。
void sort(List list,Comparator c):
//i和j处元素交换
void swap(List list,int i,int j):
//distance为整数时,将List集合后distance个元素移到前面;为负时,将前distance个元素移动后面。
void rotate(List list,int distance):
常见查找、查询操作如下:
//获得索引,且必须保证元素已处在有序状态。
nt binarySearch(List list,Object key):
Object max(Collection coll):
Object max(Collection coll,Comparator comp):
Object min(Collection coll):
Object min(Collection coll,Comparator comp):
//将指定元素obj替换指定List集合中所有元素。
void fill(List list,Object obj):
//返回出现次数
int frequency(Collection c,Object o):
//子List对象在父List对象中第一次出现的位置索引。如果没有出现这样的子List,放回-1.
int indexOfSubList(List source,List target):
//最后一次。
int lastIndexOfSubList(List source,List target):
boolean replaceAll(List list,Object oldval,Object newval):
(1)同步控制
Collections类提供多个synchronizedXxx()方法,在该方法可以将指定集合包装成线程同步的集合。
例:
public class SynchronizedTest
{
public static void main(String[] args)
{
// 下面程序创建了四个线程安全的集合对象
Collection c = Collections.synchronizedCollection(new ArrayList());
List list = Collections.synchronizedList(new ArrayList());
Set set = Collections.synchronizedSet(new HashSet());
Map map = Collections.synchronizedMap(new HashMap());
}
}
七、数组和集合比较
数组不是面向对象的,存在明显的缺陷,集合弥补了数组的缺点,比数组更灵活更实用,而且不同的集合框架类可适用不同场合。如下:
·
- 数组存放基本数据类型和对象,而集合类存放的都是对象的引用,而非对象本身。
- 数组长度固定无法动态改变,集合类容量动态改变。
- 数组无法判断其中实际存有多少元素,length只告诉了数组的容量,定义了多大的长度后,即使没有存放那么多的元素,没有存放的元素的空间就浪费了,而集合的size()可以确切知道元素的个数。
- 数组仅采用顺序表方式, 集合有多种实现方式和不同适用场合。 ·
- 集合以类的形式存在,具有封装、继承、多态等类的特性,通过简单的方法和属性即可实现各种复杂操作,大大提高了软件的开发效率。