Java 集合
1.Collection的简单介绍
1.1 分类
Collection
接口:接口的接口 – 对象的集合(单列集合)
-
List
:有序可重复集合接口,包含LinkedList
、ArrayList
、Vector
-
LinkedList
:接口实现类, 以双向链表的形式对数据进行操作- 底层为双向链表,线程不安全,效率高
-
ArrayList
:接口实现类, 以数组的形式对数据进行操作-
JDK 1.7
与JDK 1.8
的区别:- JDK 1.7:
ArrayList
像饿汉式,直接创建一个初始容量为10的数组 - JDK 1.8:
ArrayList
像懒汉式,未指定容量时,默认初始化容量是 0,当添加第一个元素时,初始化容量为 10
- JDK 1.7:
-
当超出数组的长度时会以 1.5 倍方式扩容
-
底层为数组,线程不安全,效率高
-
-
Vector
:接口实现类,同样以数组的形式对数据进行操作-
未指定容量时,默认初始化容量是 0,当添加第一个元素时,初始化容量为 10
-
当超出数组的长度时会以 2倍方式扩容
-
所有的方法都是线程同步,都加了
synchronized
关键字 -
Stack
:栈是Vector
类的实现类,其底层也是数组实现的,查询快,增删慢,线程安全,效率底
ArrayList 与 LinkedList 的比较 1.ArrayList 基于数组, LinkedList 基于链表 2.ArrayList 根据索引查询快, 根据内容查询速度几乎相当 3.ArrayList 尾部添加元素比 LinkedList 快一点(几乎可以忽略), 越靠近头部的位置添加元素, 速度越慢 - copy 的元素越多, 就越会影响效率, LinkedList 头尾添加元素都比较快, 快将近 1 倍 4.中间位置添加元素 ArrayList 明显比 LinkedList 快, 将近 4 倍
-
-
-
Set
:无序、不可重复(唯一性)集合接口,包含TreeSet
、HashSet
-
唯一性的实现:
1.存储元素时首先会使用hash()算法函数生成一个int类型hashCode散列值,然后与所存储的元素的hashCode值比较,如果hashCode不相等,肯定是不同的对象 2.hashCode值相同,再比较equals方法 3.equals相同,对象相同。(则无需储存)
-
TreeSet
:**(SortedSet接口的实现类)**底层实现为红黑树,红黑树保证了元素有序-
构造一个新的空 set,其底层 HashMap 实例的默认初始容量是 16,默认加载因子是 0.75
-
构造一个新的空 set,其底层 HashMap 实例的初始容量指定,加载因子未指定时,加载因子默认是 0.75
-
构造一个新的空 set,其底层 HashMap 实例的初始容量与加载因子均指定
-
其排序方式分为两类:
-
自然排序(无参构造),实现
Comparable
接口,重写该接口中的compareTo(T t)
方法该接口位于包
java.lang
下// Comparable源码 public interface Comparable<T> { int compareTo(T t); }
-
比较器排序(有参构造),实现
Comparator
接口,重写该接口中的compare(T o1, T o2)
方法该接口位于包
java.util
下// Comparator源码 public interface Comparator<T> { int compare(T o1, T o2); boolean equals(Object obj); }
-
-
-
HashSet
:使用hash表(数组)存储元素LinkedHashSet
:链表维护元素的插入次序
-
1.2 Collection 的常用方法
// 把给定的对象添加到当前集合中
public boolean add(E element)
// 把指定的集合中的所有元素添加到当前集合中
public boolean addAll(Collection<? extends E> c)
// 清空集合中所有的元素
public void clear()
// 判断当前集合中是否包含给定的对象
public boolean contains(E element)
// 判断当前集合中是否包含指定集合中的所有元素
public boolean containsAll(Collection<?> c)
// 将指定的对象与此集合中的元素进行比较, 相同时返回 True
public boolean equals(E element)
// 返回此集合的哈希值
public int hashCode()
// 判断当前集合是否为空
public boolean isEmpty()
// 把给定的对象在当前集合中删除
public boolean remove(E element)
// 把给定的集合中的所有元素在当前集合中删除
public boolean removeAll(Collection<?> c)
// 返回集合中元素的个数
public int size()
// 把集合中的元素,存储到数组中
public Object[] toArray()
// 把集合中的元素,存储到指定类型的数组中
public <T> T[] toArray(T[] a)
- 这些方法适用于所有能实现此接口的实现类
// 实例
import java.util.ArrayList;
import java.util.Collection;
public class Test01 {
public static void main(String[] args) {
// 创建集合对象,使用多态形式
Collection<String> c1 = new ArrayList<String>();
Collection<String> c2 = new ArrayList<String>();
// boolean add(String s)
c1.add("Hello");
c1.add("world");
c1.add("java");
c1.add("python");
System.out.println(c1);
c2.add("C语言");
c2.add("C++语言");
c2.add("go语言");
System.out.println(c2);
// boolean addAll(Collection<? extends E> c)
c1.addAll(c2);
System.out.println(c1);
// boolean contains(E e) 判断元素e是否在集合中存在
System.out.println("判断java是否在集合c1中: " + c1.contains("java"));
// boolean containsAll(Collection<?> c) 判断当前集合c1中是否包含指定集合c2中的所有元素
System.out.println("判断集合c2是否在集合c1中: " + c1.containsAll(c2));
// boolean equals(E e) : 将指定的对象与此集合中的元素进行比较, 相同时返回 True
// get() 方法为 ArrayList 特有方法, 通过下标来获取对应的对象
System.out.println("判断集合c1是存在元素python: " + c1.get(3).equals("python"));
// int hashCode() 返回此集合的哈希值
System.out.println("c1集合的哈希值为: " + c1.hashCode());
// boolean remove(E e) 删除在集合中的元素e
System.out.println("删除 C++语言: " + c1.remove("C++语言"));
System.out.println("操作之后集合中元素: " + c1);
// boolean removeAll(Collection<?> c) 把给定的集合中的所有元素在当前集合中删除
System.out.println("删除集合c1中的给定的c2集合中的所有元素: " + c1.removeAll(c2));
System.out.println("操作之后集合中元素: " + c1);
// size() 集合中有几个元素, 集合的大小
System.out.println("集合中有" + c1.size() + "个元素");
// Object[] toArray()转换成一个Object数组
Object[] objects = c1.toArray();
// 遍历数组
for (int i = 0; i < objects.length; i++) {
System.out.println(objects[i]);
}
// <T> T[] toArray(T[] a) 转换成一个指定类型的数组
String[] str = c1.toArray(new String[0]);
// 遍历数组
for (String each:str) {
System.out.println(each);
}
// void clear() 清空集合c2
c2.clear();
System.out.println("集合c2中内容为: " + c2);
// boolean isEmpty() 判断集合是否为空
System.out.println(c2.isEmpty());
}
}
-
注意:因为
Set
集合是无序的,所以无法通过索引查找对应的元素 -
List
特有的方法:-
ArrayList
与LinkedList
共有的方法:// 把指定的元素添加到当前集合中指定位置 public void add(int index, E element) // 把指定的集合中的所有元素添加到当前集合中指定位置 public boolean addAll(int index, Collection<? extends E> c) // 返回指定元素的第一次出现的索引, 如果不存在就返回 -1 public int indexOf(E element) // 返回指定元素的最后一次出现的索引 public int lastIndexOf(E element) // 删除该集合中指定位置的元素, 返回删除的元素 public E remove(int index) // 用指定的元素替换此集合中指定位置的元素, 并将指定位置的元素返回 public E set(int index, E element) // 将指定索引位置的元素返回 public E get(int index)
-
ArrayList
特有的方法// 从这个集合中删除所有索引在 (包含)fromIndex 和 toIndex(不包含) 之间的元素 protected void removeRange(int fromIndex, int toIndex) // 使用提供的 Comparator 对此集合进行排序以比较元素(注意要重写其compare方法) public void sort(Comparator<? super E> c) // 返回该集合中从 fromIndex 到 toIndex 之间的所有元素构成的一个子集合 public List<E> subList(int fromIndex, int toIndex) // 修改这个 ArrayList实例的容量是列表的当前大小 public void trimToSize()
-
LinkedList
特有的方法 -
注意:
LinkedList
实现Deque
与Queue
接口,即能将LinkedList
当作双端队列使用
// 把指定的元素插入到当前集合开头 public void addFirst(E e) // 把指定的元素追加到当前集合末尾 public void addLast(E e) // 返回此集合中的第一个元素 public E getFirst() // 返回此集合中的最后一个元素 public E getLast() // 从此集合表示的堆栈中弹出一个元素 --> 相当于removeFirst() public E pop() // 将指定元素推送到由此集合表示的堆栈上 --> 相当于addFirst(E e) public void push(E e) // 从此集合中删除并返回第一个元素 public E removeFirst() // 从此集合中删除并返回第一个元素 public E removeLast() // 以上为比较常见的方法 ---------------------------------------------分割线--------------------------------------------------- // 以下为较少运用的方法 // 检索但不删除此集合的头(第一个元素), 并将其返回 public E element() public E peek() // 检索但不删除此集合的第一个元素,如果此集合为空,则返回 null public E peekFirst() // 检索但不删除此集合的最后一个元素,如果此集合为空,则返回 null public E peekLast() // 检索并删除此集合的头(第一个元素) public E poll() // 检索并删除此集合的第一个元素,如果此集合为空,则返回 null public E pollFirst() // 检索并删除此集合的最后一个元素,如果此集合为空,则返回 null public E pollLast() // 将指定的元素添加为此集合的末尾 public boolean offer(E e) // 在此集合的前面插入指定的元素 public boolean offerFirst(E e) // 在该集合的末尾插入指定的元素 public boolean offerLast(E e) // 删除此集合中第一个出现的指定元素 public boolean removeFirstOccurrence() // 删除此集合中最后一个出现的指定元素 public boolean removeLastOccurrence()
-
-
Set
继承自Collection
,拥有其父类的所有方法-
TreeSet
特有的方法// 返回此集合中大于或等于给定元素的最小元素, 如果没有此元素, 则返回 null public E ceiling(E e) // 返回对此 set 中的元素进行排序的比较器; 如果此 set 使用其元素的自然顺序, 则返回 null public Comparator<? super E> comparator() // 返回在此 set 元素上按降序进行迭代的迭代器 public Iterator<E> descendingIterator() // 返回此 set 中所包含元素的逆序视图 public NavigableSet<E> descendingSet() // 返回此 set 中当前第一个(最低)元素 public E first() // 返回此 set 中小于等于给定元素的最大元素;如果不存在这样的元素, 则返回 null public E floor(E e) // 返回此 set 的部分视图,其元素严格小于 toElement public SortedSet<E> headSet(E toElement) // 返回此 set 的部分视图, 其元素小于(或等于, 如果 inclusive 为 true)toElement public NavigableSet<E> headSet(E toElement, boolean inclusive) // 返回此 set 中严格大于给定元素的最小元素; 如果不存在这样的元素, 则返回 null public E higher(E e) // 返回在此 set 中的元素上按升序进行迭代的迭代器 public Iterator<E> iterator() // 返回此 set 中当前最后一个(最高)元素 public E last() // 返回此 set 中严格小于给定元素的最大元素; 如果不存在这样的元素, 则返回 null public E lower(E e) // 获取并移除第一个(最低)元素; 如果此 set 为空, 则返回 null public E pollFirst() // 获取并移除最后一个(最高)元素; 如果此 set 为空, 则返回 null public E pollLast() // 返回此 set 的部分视图, 其元素范围从 fromElement 到 toElement public NavigableSet<E> subSet(E fromElement, boolean fromInclusive, E toElement, boolean toInclusive) // 返回此 set 的部分视图, 其元素从 fromElement(包括) 到 toElement(不包括) public SortedSet<E> subSet(E fromElement, E toElement) // 返回此 set 的部分视图, 其元素大于等于 fromElement public SortedSet<E> tailSet(E fromElement) // 返回此 set 的部分视图, 其元素大于(或等于, 如果 inclusive 为 true) fromElement public NavigableSet<E> tailSet(E fromElement, boolean inclusive) /** * 注意: * 1.new TreeSet<>(); 无参构造生成对象时, 会进行自然排序 * 2.new TreeSet<T>(new Comparator<T>() { * // 自定义比较器,保证顺序 * @Override * public int compare(T t1, T t2) { * int num = t1.getXXX() - t2.getXXX(); * num = (num == 0 ? (t1.hashCode() - t2.hashCode()):num); * return num; * } * }); 有参构造时需要自定义比较器 * * */
-
HashSet
没有特有的方法与
List
基本使用一致,只是输出顺序并不是存入数据时的顺序 -
LinkedHashSet
-
1.3 Collection 集合的使用
2.Map 详解
2.1 分类
Map
接口: 键值对的集合 (双列集合)
Hashtable:
底层是哈希表数据结构, 线程是同步的, 不可以存入null键, null值; 效率较低, 被 HashMap 替代
HashMap:
底层是哈希表数据结构, 线程是不同步的, 可以存入null键, null值
要保证键的唯一性, 需要覆盖hashCode方法和equals方法
LinkedHashMap:
HashMap的子类基于哈希表又融入了链表; 可以为Map集合进行增删提高效率。
TreeMap:
TreeMap底层是二叉树数据结构, 可以对集合中的键进行排序
键的排序实现:
方式一: 元素自身具备比较性
和TreeSet一样原理, 需要让存储在键位置的对象实现Comparable接口, 重写compareTo方法, 也就是让元素自身具备比较性, 这种方式叫做元素的自然排序也叫做默认排序
方式二: 容器具备比较性
当元素自身不具备比较性, 或者自身具备的比较性不是所需要的时候, 此时可以让容器自身具备 --> 定义一个类实现 Comparator接口, 重写compare方法, 并将该接口的子类实例对象作为参数传递给TreeMap集合的构造方法
注意: 当Comparable比较方式和Comparator比较方式同时存在时, 以Comparator的比较方式为主;在重写compareTo或者compare方法 时,必须要明确比较的主要条件相等时要比较次要条件
2.2 常用方法
public class MethodsInfo {
// 删除所有的映射
public void clear()
// 判断该Map集合是否包含指定的键
public boolean containsKey(Object key)
// 判断该Map集合是否包含指定键的值
public boolean containsValue(Object value)
// 判断该Map集合中是否存在与指定对象相等的映射
public boolean equals(Object o)
// 判断该Map集合是否为空
public boolean isEmpty()
// (如果此映射包含该键的映射)返回到指定键所映射的值
public V get(Object key)
// 返回该Map集合的哈希码值
public int hashCode()
// 返回此Map集合中键值映射的数量
public int size()
// 返回一个包含了该Map集合所有键值对的Set集合
public Set<Map.Entry<K,V>> entrySet()
// 返回一个包含该Map集合所有的键的Set集合
public Set<K> keySet()
// 返回此Map集合中包含所有键的值的Collection集合
public Collection<V> values()
// 将指定的值与该映射中的指定键添加到该Map集合中去
public V put(K key, V value)
// 将指定的一个Map集合的所有映射复制到此Map集合中去
public void putAll(Map<? extends K,? extends V> m)
// 从该Map集合中删除一个指定键的映射
public V remove(Object key)
}
2.3 常用子类
-
HashMap
-
底层实现
JDK 1.8 之前 数组 + 链表 – 添加元素-头插法
JDK 1.8之后 数组 + 链表|红黑树 – 添加元素-尾插法
1.为何要使用红黑树? 红黑树用来避免 DoS 攻击,防止链表超长时性能下降,树化应当是偶然情况,是保底策略 2.为何一开始不使用红黑树? hash 表的查找,更新的时间复杂度是 O(1),而红黑树的查找,更新的时间复杂度是 O(lgn/lg2) TreeNode 占用空间也比普通 Node 的大,如非必要,尽量还是使用链表 3.红黑树的阈值为何为 8 hash 值如果足够随机, 则在 hash 表内按泊松分布 在负载因子 0.75 的情况下, 长度超过 8 的链表出现概率是 0.00000006, 树化阈值选择 8 就是为了让树化几率足够小 4.什么时候会树化? 链表长度大于树化阈值8并且数组容量大于64 5.什么时候会退化为链表 a.在扩容时如果拆分树时, 树元素个数 <= 6 则会退化链表 b.remove 树节点时, 若 root、root.left、root.right、root.left.left 有一个为 null,也会退化为链表 c.检测为退化前的链表 - 移除以上任意一个节点后, 还不会退化, 再一次移除任意一个节点, 就会退化 6.索引如何计算 a.先计算对象的 hashCode() , 在调用 hash() 方法二次哈希 b.最后与数组容量进行取余运算 % capacity 或者与数组容量减一进行与运算 & (capacity - 1) 获得索引 7.hashCode 已经存在, 为何还需要 hash() 方法 二次哈希是为了综合高位数据, 让哈希分布更为均匀 8.数组容量为何为 2 的 n 次幂 a.计算索引时效率更高 b.链表元素扩容时:hash & oldCap == 0 的元素留在原来的位置, 否则新位置 = 旧位置 + oldCap
-
初始化容量大小为 16, 负载因子为 0.75
-
当超过 初始化大小*负载因子时,就会触发扩容机制 - 扩容为原来的2倍
-
-
TreeMap
关于 Set 集合,因为个人使用不多,所有有些地方总结不到位,还请各位小伙伴指正,谢谢您的浏览阅读
有任何错误请指正,谢谢您的阅读,希望对您有所帮助。