1、Collection 接口
Collection是单例集合的顶层接口,它表示一组对象,这些对象被称为Collection元素,JDK不提供此接口的任何直接实现,它提供更加具体的子接口Set和List实现。创建Collection集合的对象采用多态的方式、具体实现类ArrayList。(Collection单例集合有:ArrayList、LinkedList、TreeSet、HashSet)(Map双例集合有:HashMap、Hashtable、ConcurrentHashMap)
常用方法:
boolean add(E e)
将指定的元素附加到此列表的末尾。
void clear()
从此列表中删除所有元素。
boolean contains(Object o)
返回true此列表是否包含指定的元素。
boolean remove(Object o)
从此列表中删除第一次出现的指定元素(如果存在)。
Object[] toArray()
以适当的顺序(从第一个元素到最后一个元素)返回一个包含此列表中所有元素的数组。
Iterator iterator()
返回此集合中元素的迭代器
boolean equals(Object o)
比较指定对象与此集合是否相等。
int hashCode()
返回此集合的哈希码值。
int size()
返回此集合中的元素数
1.1 List接口
list集合是有序集合,也被成为序列,用户可以精确控制每个元素在列表中的插入位置。用户可以通过它们的整数索引(在列表中的位置)访问元素,并在列表中搜索元素。与set集合不同,列表通常允许重复元素。
List集合特点:可重复,有序
常用子类:ArrayList、LinkedList 和 Vector(不推荐使用)
1.1.1、ArrayList 集合(优先考虑)
概念:List接口的可调整大小的数组实现。实现所有可选的列表操作,并允许所有元素,包括null. 除了实现List接口之外,该类还提供了操作内部用于存储列表的数组大小的方法。
特点:基于数组实现,查找效率高,但新增和删除效率低;线程不安全。
特有方法
void add(int index, E element)
在此列表中的指定位置插入指定元素。
E get(int index)
返回此列表中指定位置的元素。
int indexOf(Object o)
返回此列表中指定元素第一次出现的索引,如果此列表不包含该元素,则返回 -1。
int lastIndexOf(Object o)
返回此列表中指定元素最后一次出现的索引,如果此列表不包含该元素,则返回 -1。
E remove(int index)
移除此列表中指定位置的元素。
E set(int index, E element)
用指定的元素替换此列表中指定位置的元素。
ArrayList<String> list = new ArrayList<>();
list.add("英伟达");
list.add("英特尔");
list.add("AMD");
list.add(2,"死亡之眼");
System.out.println(list.contains("AMD"));
System.out.println(list.get(0));
System.out.println(list.indexOf("AMD"));
System.out.println(list.lastIndexOf("AMD"));
System.out.println(list.remove(0));
System.out.println(list.remove("AMD"));
System.out.println(list.set(1,"Inter"));//返回被替代的元素
Object[] str=list.toArray();
System.out.println(Arrays.toString(str));
1.1.2 LinkedList
概念:LinkedList同时实现了List接口和Deque接口,也就是收它既可以看作一个顺序容器,又可以看作一个队列(Queue),同时又可以看作一个栈(stack)
特点:底层数据结构是链表,查询慢,增删快。线程不安全,效率高。
特有方法:
void addFirst(E e) 在此列表的开头插入指定的元素。
void addLast(E e)将指定的元素附加到此列表的末尾。
E getFirst() 返回此列表中的第一个元素。
E getLast() 返回此列表中的最后一个元素。
E removeFirst() 移除并返回此列表中的第一个元素。
E removeLast() 从此列表中删除并返回最后一个元素。
1.1.3 Vector
概念:Vector类实现可增长的对象阵列。像数组一样,它包含可以使用整数索引访问的组件
特点:线程安全,但是效率低
1.2 Set 接口
与List集合不同,Set接口的实现类创建的集合都是不包含重复元素的集合
Set集合特点:不包含重复元素的集合、没有带索引的方法所以不能使用普通遍历
常用子类:TreeSet(排序使用)、HashSet(效率高)、LinkedHashSet
1.2.1 TreeSet
概念:底层是二叉树算法实现。被用作排序
特点:元素不重复、排序根据传入参数进行排序(无参构造函数进行自然排序,带参构造函数根据参数排序接口排序)。没有索引,只能使用迭代器或增强for循环遍历
无参构造函数排序(需要Student类实现 Comparable接口,重写public int compareTo(Student s)方法;方法内容为排序规则)
@Override
public int compareTo(Student s) {
// return 0;//只会添加一个进集合
// return 1;//按存储顺序添加进集合
// return -1;//按存储顺序逆序添加进集合
int num=this.age-s.age;//按照年龄大小升序排列
// int num=s.age-this.age;//按照年龄大小降序排列
int num2= num==0?this.name.compareTo(s.name):num;
return num2;
}
带参构造函数排序(1、用匿名内部类)
TreeSet<Student> ts = new TreeSet<>(new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
int num=s1.getAge()-s2.getAge();
int num2= num==0?s1.getName().compareTo(s2.getName()):num;
return num2;
}
});
(2、使用 static void sort(T[] a, Comparator<? super T> c)
根据由指定的比较器得出的顺序对指定的对象数组进行排序。)
1.2.2 HashSet
概念:底层数据结构是哈希表,对集合的迭代顺序不作任何保证,也就是说不保证存储和取出的顺序一致、没有带索引的方法,所以不能使用普通for循环遍历、由于是Set集合,所以不包含重复元素的集合
原理:利用了哈希算法,在调用add方法时计算出对象的哈希值,用计算出的哈希值在集合中对比,没有相同则存入,如果有则用equals一个一个比较,比较结果为false则存入,true则不存。
使用HashSet时要重写类里面的hashCode和equals方法。
public static void main(String[] args) {
HashSet<Student> hash = new HashSet<>();
Student s1 = new Student("张三", 20);
Student s2 = new Student("李四", 20);
Student s3 = new Student("王五", 20);
Student s4 = new Student("王五", 20);
hash.add(s1);
hash.add(s2);
hash.add(s3);
hash.add(s4);
for (Student hashs:hash){
System.out.println(hashs);
}
}
1.2.3 LinkedHashSet
特点:哈希表和链表实现Set接口具有可预测的迭代性、链表保证元素的有序、哈希表保证元素的唯一
初始容量为16,散列因子0.75。继承于HashSet,又基于LinkedHashMap存储所有元素,并用双向链表记录插入顺序
2、Map接口
Map接口下常用的子类有HashMap 、TreeMap 、Hashtable 和 ConcurrentHashMap 实现类,Map集合可以存储一对对象,即会一次性保存两个对象,存在key = value 结构,其最大的特点还是可以通过key 找到对应的value 值。
2.1 HashMap(常用)
实现原理:
- HashMap根据计算出的哈希值对容量的取余获得集合操作下标。
- 调用put方法时,需要检查数组大小,如果大于阈值则扩容
- 计算哈希值,判断是否已有元素,无则直接插入,有则再判断是否存在key,存在则覆盖旧值,不存在则生成链表
常用方法:
V put(K key, V value)
将指定值与此映射中的指定键相关联。
boolean containsKey(Object key)
返回true此映射是否包含指定键的映射。
boolean containsValue(Object value)
返回true此映射是否将一个或多个键映射到指定值。
Set<Map.Entry<K,V>> entrySet()
返回Set此映射中包含的映射的视图。
Set keySet()
返回Set此映射中包含的键的视图。
Collection values()
返回Collection此映射中包含的值的视图。
HashMap<Student, String> hm = new HashMap<>();
Student s1 = new Student("刘备", 30,"蜀国");
Student s2 = new Student("黄盖", 40,"东吴");
Student s3 = new Student("周瑜", 27,"东吴");
Student s4 = new Student("小乔", 24,"东吴");
Student s5 = new Student("小乔", 25,"东吴");
hm.put(s1,"蜀国");
hm.put(s2,"东吴");
hm.put(s3,"东吴");
hm.put(s4,"东吴");
hm.put(s5,"大汉");
System.out.println(hm.containsKey(s1));
System.out.println(hm.containsValue("大汉"));
Set<Map.Entry<Student, String>> entries = hm.entrySet();
for (Map.Entry<Student, String> entry:entries){
String value = entry.getValue();
System.out.println(entry.getKey().name+"来自"+value);
}
Set<Student> keys = hm.keySet();
for (Student key:keys){
System.out.print(key.getName()+" ");
}
System.out.println();
Collection<String> values = hm.values();
for (String value:values){
System.out.print(value+" ");
}
2.2 Hashtable
很多映射的常用功能与HashMap类似,不同的是它继承自Dictionary类,并且是线程安全的,任一时间只有一个线程能写Hashtable
2.3 TreeMap(推荐需要排序时使用)
TreeMap实现SortedMap<K,V>接口,能够把它保存的记录根据键排序,默认是按键值的升序排序,也可以指定排序的比较器,当用Iterator遍历TreeMap时,得到的结果是排过序的。
使用TreeMap时,key必须实现Comparable接口或者在构造TreeMap传入自定义的Comparator,否则会在运行时抛出java.lang.ClassCastException类型的异常。
2.4 ConcurrentHashMap(推荐需要线程安全时使用)
线程安全原理:采用分段锁机制
很多映射的常用功能与HashMap类似
2.5 LinkedHashMap
LinkedHashMap是HashMap的一个子类,保存了记录的插入顺序,在用Iterator遍历LinkedHashMap时,先得到的记录肯定是先插入的,也可以在构造时带参数,按照访问次序排序。
2.6 HashMap、Hashtable、ConcurrentHashMap的区别
相同点:都是数据容器
不同点:
HashMap 线程不安全、效率高 、不保证存储顺序
Hashtable 线程安全、效率低 、不保证存储顺序
ConcurrentHashMap 线程安全、效率比较高(采用分段锁机制)不保证存储顺序
TreeMap 不保证存储顺序,但是会自动排序
LinkedHashMap 既保证存储顺序也保证查找方便
PS:将对象当成key存储时一定不要更改它,特别是自定义对象,容易发生数据结构错乱,会改变哈希值,导致查找的时候找不到。
3、哈希表概述
哈希表是一种数据结构,由对象数组+链表组成。根据哈希值对数组长度取余获取数组下标。对数据进行操作。默认哈希桶是16,散列因子0.75(当哈希桶存在数据75%时会进行扩容,扩容2倍,重构数据结构)。
PS: 在创建哈希表要思考好初始的桶数,过小容易多次重构数据结构,浪费性能,过大容易浪费空间。
散列因子过大虽然会减少空间的消耗,但是会增加查找成本,过小则会浪费大量空间。
哈希冲突
如果在计算哈希值得到数组下标后发现数组内存在数据,会生成一个链表,将数据存放到原数据后。
1.8版本新特性:
存放数据的数组空间被称为哈希桶
当哈希桶中的数据量大于8时,桶中的链表转换为红黑二叉树
当哈希桶中的数据量减少到6时,红黑二叉树转换为链表
4、迭代器和增强for循环
4.1 迭代器
4.1.1 Iterator
Iterator是一个接口,它是集合的迭代器。集合可以通过Iterator去遍历集合中的元素。
使用方法如下:
public static void main(String[] args) {
Collection<String> ct = new ArrayList<String>();
ct.add("hello");
ct.add("java");
ct.add("javase");
ct.add("javaee");
System.out.println(ct.contains("hello"));//判断集合中是否有这个元素
//Iterator<E> iterator() 返回此集合中元素的迭代器。
Iterator<String> it = ct.iterator();//Iterator<E> iterator() 返回此集合中元素的迭代器。
while (it.hasNext()){//boolean hasNext() true如果迭代有更多元素,则返回
String s = it.next();//E next() 返回迭代中的下一个元素。
System.out.println(s);
}
}
4.1.2 ListIterator
ListIterator列表的迭代器,允许程序员沿任一方向遍历列表,在迭代期间修改列表,并获取迭代器在列表中的当前位置。它继承于Iterator接口,只能用于各种List类型的访问。
常用方法
E next()
返回列表中的下一个元素并前进光标位置。
E previous()
返回列表中的前一个元素并向后移动光标位置。
int nextIndex()
返回后续调用将返回的元素的索引next()。
int previousIndex()
返回后续调用将返回的元素的索引previous()。
void remove()
从列表中删除由next()or返回的最后一个元素previous()(可选操作)。
void set(E e)
用指定元素替换next()或 返回的最后一个元素previous()(可选操作)。
public static void main(String args[]){
// List.listIterator()列表的迭代器,允许程序员沿任一方向遍历列表,在迭代期间修改列表,并获取迭代器在列表中的当前位置
ListIterator<String> lit = list.listIterator();
//boolean hasPrevious()
//返回true此列表迭代器在反向遍历列表时是否有更多元素。
while (lit.hasPrevious()){
String s = lit.previous();
System.out.println(s);
}
while (lit.hasNext()){
String s=lit.next();
if(s.equals("Java")){
lit.add("java");//void add(E e)将指定的元素插入列表(可选操作)。不会发生并发异常
}
}
System.out.println(list);
}
4.2 增强for循环
目的:简化数组和Collection、Map集合的遍历
增强的格式
for(元素数据类型 变量名:数组或Collection集合){
元素就是变量名