跳到主要内容

集合

1.集合框架概述

  • 集合 Collection The Collection in Java is a framework that provides an architecture to store and manipulate the group of objects.

    数组同样也是对多个数据进行存储操作的结构(此时的存储指内存层面的此时,不涉及持久化的存储)

  1. 数组存储的特点

    1. 长度固定:一旦初始化完毕,其长度就不可修改
    2. 数组类型固定:数组定义好后,只能操作指定类型的数据
  2. 数组存储的弊端

    1. 长度不可修改:初始化后,同一个数组对象长度不可再修改
    2. 增删改效率低
    3. 缺乏属性或方法
    4. 无法满足无序、不可重复的需求:数组的存储特点是有序、可重复
  3. 集合的优点

    1. 动态长度
    2. 增删改效率高
    3. 相应属性或方法
    4. 有无序、不可重复的Set接口,也有有序、可重复的List接口
  4. 接口继承树

2. Collection接口

2.1 概述

Collection是单列数据,定义了存取一组对象的方法的集合。

Collection接口是List、Set和Queue接口的父接口,在JDK1.5之前,集合会丢掉容器中所有对象的数据类型,在JDK1.5加了泛型之后,集合可以记住容器中所有对象的数据类型。

2.2 方法

  1. 添加

    add(Object obj)

    addAll(Collection coll)

  2. 获取有效元素的个数

    int size()

  3. 清空集合

    void clear()

  4. 是否是空集合

    boolean isEmpty()

  5. 是否包含某个元素

    boolean contains(Object obj):是通过元素的equals方法来判断是否是同一个对象

    boolean containsAll(Collection c):也是调用元素的equals方法来比较的。比较集合中是否包含c集合中的所有元素

  6. 删除

    boolean remove(Object obj) :通过元素的equals方法判断是否是要删除的那个元素。只会删除找到的第一个元素

    boolean removeAll(Collection coll):取当前集合的差集

  7. 取两个集合的交集

    boolean retainAll(Collection c):把交集的结果存在当前集合中,不影响c

  8. 集合是否相等(注意顺序)

    boolean equals(Object obj)

  9. 转成对象数组

    Object[] toArray()

  10. 获取集合对象的哈希值

    hashCode()

  11. 遍历

    iterator():返回迭代器对象,用于集合遍历

2.3 集合和数组的转换

  1. 集合到数组:Collection的toArray()方法

        Collection coll1 = new ArrayList();
    coll1.add(123);
    coll1.add("abc");
    coll1.add(new Person("Tom", 18));


    Object[] os = coll1.toArray();
    for (Object o : os) {
    System.out.println(o);
    }
    /*Output
    123
    abc
    Person{name='Tom', age=18}
    */
  2. 数组到集合:Arrays的asList()方法

    Collection coll2 = new ArrayList();
    String[] str = new String[]{"AA", "BB", "CC"};
    coll2 = Arrays.asList(str);
    coll2.forEach(String -> System.out.println(String));
    /*Output
    AA
    BB
    CC
    */
    • 深入Arrays的asList()方法

      首先查看asList()方法的源码

      public static <T> List<T> asList(T... a) {
      return new ArrayList<>(a);
      }

      返回的ArrayList类是Arrays的私有类ArrayList,它同样实现了AbstractList接口

      private static class ArrayList<E> extends AbstractList<E>
      implements RandomAccess, java.io.Serializable
      {
      ...
      private final E[] a;

      ArrayList(E[] array) {
      a = Objects.requireNonNull(array);
      }
      ....
      }

      可以看到,Arrays中的ArrayList和List接口的ArrayList类是不同的

      String[] str = new String[]{"AA", "BB", "CC"};
      //此时不再向上转型
      ArrayList coll3 = new ArrayList();
      coll3 = Arrays.asList(str);//报错

3.Iterator迭代器接口

3.1 概述

  • Iterator迭代器主要用于遍历Collection集合中的元素

    在设计模式中,迭代器提供一种方式访问一个容器对象中各个元素,而又不暴露该对象的内部细节

  • Collection接口继承了java.lang.Iterable接口,该接口有一个Iterator()方法,每次调用Iterator()方法都会返回一个全新的Iterator对象

3.2 方法

Iterator方法

Modifier and TypeMethod and Description
default voidforEachRemaining(Consumer action)
Performs the given action for each remaining element until all elements have been processed or the action throws an exception.
booleanhasNext()
Returns true if the iteration has more elements.
Enext()
Returns the next element in the iteration.
default voidremove()
Removes from the underlying collection the last element returned by this iterator (optional operation).

Code

使用hasNext()、next()、remove()方法

public class IteratorTest {
public static void main(String[] args) {
Collection coll = new ArrayList();
coll.add(123);
coll.add(456);
coll.add(new Person("Jerry",20));
coll.add(new String("Hello"));
coll.add(false);

Iterator iterator = coll.iterator();

//remove方法
while (iterator.hasNext()){
Object o = iterator.next();
if(o.equals(123)){
iterator.remove();
}
}

iterator = coll.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
/*Output:
456
Person{name='Jerry', age=20}
Hello
false
*/

}
}

3.3 遍历集合的四种方式

先构建一个集合,并添加测试数据

Collection coll = new ArrayList();
coll.add(123);
coll.add(456);
coll.add(new Person("Jerry",20));
coll.add(new String("Hello"));
coll.add(false);

方式一:使用Iterator结合while循环

Iterator iterator = coll.iterator();
//方式一:使用while循环
while(iterator.hasNext()){
System.out.println(iterator.next());
}

方式二:使用foreach语句,本质还是调用Iterator迭代器

for (Object o : coll){
System.out.println(o);
}

方式三:使用Iterator中的forEachRemaining()方法结合Lambda表达式

Iterator iterator = coll.iterator();
//方式三:使用forEachRemaining()方法
iterator.forEachRemaining((Object o)-> System.out.println(o));
//再次遍历输出为空
iterator.forEachRemaining((Object o)-> System.out.println(o));

方式四:使用集合中的forEach()方法结合Lambda表达式

//方式四:使用forEach()方法
coll.forEach((Object o)-> System.out.println(o));
//forEach()方法可多次遍历
coll.forEach((Object o)-> System.out.println(o));

方法引用:

coll.forEach(System.out::println);

参考博客:方法引用

4.Collection子接口之一:List接口

4.1 List接口概述

  • List中元素可有序、可重复

4.2 List接口方法

List除了Collection接口外,还增加了一些根据索引来操作集合元素的

  • void add(int index, Object ele):在index位置插入ele元素
  • boolean addAll(int index, Collection eles):从index位置开始将eles中 的所有元素添加进来
  • Object get(int index):获取指定index位置的元素
  • int indexOf(Object obj):返回obj在集合中首次出现的位置
  • int lastIndexOf(Object obj):返回obj在当前集合中末次出现的位置
  • Object remove(int index):移除指定index位置的元素,并返回此元素
  • Object set(int index, Object ele):设置指定index位置的元素为ele
  • List subList(int fromIndex, int toIndex):返回从fromIndex到toIndex位置的子集合

4.3 List三个实现类

  1. java.util.Arraylist:JDK1.2开始,最主要、最常用的实现类,底层使用Object[] elementData存储,线程不安全但效率高
  2. java.util.LinkedList:JDK1.2开始,一般使用在频繁增删的场景,底层使用双向链表存储
  3. java.util.Vector:JDK1.1开始,线程安全但效率低,底层也是使用Object[] elementData存储

4.3.1 List实现类之一:ArrayList

  • JDK1.8之前:类似饿汉式,直接创建容量为10的Object数组,扩容时以原先数组的1.5倍起
  • JDK1.8:类似懒汉式,第一次调用时才创建容量为10的Object数组,扩容时同JDK1.8之前

4.3.2 List实现类之二:LinkedList

底层是双向链表

    private static class Node<E> {
E item;
Node<E> next;
Node<E> prev;

Node(Node<E> prev, E element, Node<E> next) {
this.item = element;
this.next = next;
this.prev = prev;
}
}

4.3.3 List实现类之三:Vector

不常用

5. Collection子接口之二:Set接口

5.1 Set接口概述

5.1.1 Set特性

  • Set中元素无序、不可重复

    • 无序性:Set的底层也是数组,它存储数据的规则是按照数据的哈希值来决定的,所以这也决定了元素存放位置的数组索引不等于添加顺序。
    • 不可重复:保证添加的元素按照equals()方法判断时,不能返回true
  • Set判断两个对象相关不是用==,而是用equals()方法

    Set判断两个对象相关是用equals()方法,如果类没有重写equals()方法,那么它会调用Object类中的equals()方法,Object的equals()方法底层仍是使用==

  • Set中没有额外定义新的方法,使用的都是Collection声明的方法

5.1.2 Set添加元素的过程

以HashSet为例:

向HashSet添加元素a时,首先调用元素a所在类的hashCode()方法,得到a的hash值,接着使用该hash值经过某种算法计算出a应该在HashSet底层数组的存放位置

如果该存放位置为空,则直接添加元素a

如果存放位置有b,则调用a所在类的equals方法进行比较

​ 如果相等,则添加失败

​ 如果不等,则添加a(以链表的方式添加,JDK8中会让b仍存在原来的数组中,然后指向a)

5.2 Set三个实现类

  • java.util.HashSet
    • 作为Set的主要实现类
    • 线程不安全
    • 可以存储一个null
  • java.util.LinkedHashSet
    • HashSet的子类
    • 遍历内部数据时,可以按照添加时的顺序遍历
  • java.util.TreeSet
    • 可以按照添加对象的指定属性进行排序

5.2.1 Set实现类之一:HashSet

5.2.2 Set实现类之二:LinkedHashSet

  • HashSet的子类
  • LinkedHashSet使用双向链表维护元素的次序
  • 对于频繁的遍历操作,LinkedHashSet效率高于HashSet

5.2.3 Set实现类之三:TreeSet

  1. 只能添加相同类的对象
  2. 会按照添加对象的属性去排序

CODE

代码一

public class TreeSetTest {
public static void main(String[] args) {
TreeSet set = new TreeSet();
set.add(129);
set.add(-1);
set.add(30);
set.add(4);

set.forEach((o)-> System.out.println(o));
/*Output:
-1
4
30
129
*/
}
}

代码二

让Person类实现Comparable接口,实现接口的compareTo()方法,比较name

public class Person implements Comparable{
private String name;
private int age;

//省略

@Override
public int compareTo(Object o) {
if(o instanceof Person){
Person person = (Person)o;
return this.name.compareTo(person.name);
}else{
throw new RuntimeException("The type of input is mismatch################");
}
}
}

在TreeSet中添加Person类

public class TreeSetTest {
public static void main(String[] args) {
TreeSet set = new TreeSet();
set.add(new Person("Tom",13));
set.add(new Person("Jerry",2));
set.add(new Person("Mike",31));
set.add(new Person("Jack",80));


set.forEach((o)-> System.out.println(o));
/*Output
Person{name='Jack', age=80}
Person{name='Jerry', age=2}
Person{name='Mike', age=31}
Person{name='Tom', age=13}
*/

}
}

6.Map接口

6.1 概述

Map和Collection并列存在,所以称呼集合并不准确,更好的应该是称呼为容器,集合是容器的一个子集。

Map数列数据,用于保存具有映射关系的键值对:key-value

Map中的key用set进行存放,不允许重复,

key所在的类要重写equals()方法和hashCode()方法,而value所在的类要重写equals(),hashCode()方法在储存时被调用

常用的实现类是HashMap

主要实现类:

  • HashMap:线程不安全,效率高;可以存储null的key和value

    JDK1.8之前,HashMap底层是数组+链表,JDK1.8之后,底层是数组+链表+红黑树

    • 子类LinkedHashMap:遍历元素时,可以按照添加的顺序实现遍历,其原理同LinkedHashSet一样,每个元素添加一对指针来维护其顺序

      当频繁增删数据时,LinkedHashMap效率高于HashMap

  • TreeMap:保证按照添加的key-value进行排序,实现排序遍历,此时考虑key的自然排序或者定制排序

  • HashMap:线程安全,效率低;可以存储null的key和value

    • 子类Properties:常用来处理配置文件,key和value都是String类型
public class TestMap {
public static void main(String[] args) {
Map<String,Integer> map = new HashMap<>();
Map<String,Integer> map2 = new Hashtable<>();

map.put(null, null);
map.put("1",null);

// map2.put(null, null); //编译通过,运行时报空指针异常
// map2.put("1",null); //同样报空指针异常
}
}

6.2 Map的常用方法

  • 添加、删除、修改操作:

    • V put(K key,Object V):将指定key-value添加到(或修改)当前map对象中

      返回值中,如果为null表明做的是添加操作,如果返回的不是null,那么此时做的是修改操作,它返回的是key的上一个值

      Map<String,Integer> map = new HashMap<>();
      map.put("A", 1);
      int a = map.put("A",2);
      System.out.println("a="+a);
      /*Output:
      a=1
      */
    • void putAll(Map m):将m中的所有key-value对存放到当前map中

    • V remove(K key):移除指定key的key-value对,并返回value

    • void clear():清空当前map中的所有数据

  • 元素查询的操作:

    • V get(V key):获取指定key对应的value
    • boolean containsKey(K key):是否包含指定的key
    • boolean containsValue(V value):是否包含指定的value
    • int size():返回map中key-value对的个数
    • boolean isEmpty():判断当前map是否为空
    • boolean equals(Object o):判断当前map和参数对象obj是否相等
  • 元视图操作的方法:

    • Set<K> keySet():返回所有key构成的Set集合
    • Collection<V> values():返回所有value构成的Collection集合
    • Set<Map.Entry<K,V>> entrySet():返回所有key-value对构成的Set集合

遍历map元素:

Map<String,Integer> map = new HashMap<>();
map.put("A",1);
map.put("B",2);
map.put("C",3);

Set<Map.Entry<String,Integer>> entrySet = map.entrySet();
Iterator<Map.Entry<String, Integer>> iterator = entrySet.iterator();
while(iterator.hasNext()){
Map.Entry<String,Integer> entry = iterator.next();
System.out.println(entry.getKey()+":"+entry.getValue());
}
/*Output
A:1
B:2
C:3
*/

6.3 Map的实现类

6.3.1 Map实现类之一:java.util.HashMap类

  • jdk1.8之前的HashMap存储结构:数组+链表

实例化之后,底层创建一个长度是16的一维数组Entry[] table

当重复put同一个key的时候,新的value会替代原来的value;

默认的扩容方式:当超出阈值并且要存放的位置非空时,会扩容为原来的两倍,并将原有的数据复制过来;

  • jdk1.8之后的HashMap存储结构

JDK8的改变

  1. new HashMap()实例化之后不会创建数组,而是在调用put()方法时才会创建一个长度为16的数组(饿汉式-->懒汉式)
  2. 底层数组是Node(),而非Entry()
  3. 数组上某一个索引的位置数据个数大于8并且当前数组长度大于64(小于64时会先扩容数组直到64)时,此索引位置的所有数据从原先链表存储改为红黑树存储

重要的源码常量

DEFAULT_INITIAL_CAPACITY : HashMap的默认容量,16

DEFAULT_LOAD_FACTOR:HashMap的默认加载因子,0.75

threshold:需要扩容的阈值,=容量*加载因子,刚开始为16*0.75=12

TREEIFY_THRESHOLD:Bucket中链表长度大于该默认值,转化为红黑树,8

MIN_TREEIFY_CAPACITY:桶中的Node被树化时最小的hash表容量。64

6.3.2 Map实现类之二:java.util.LinkedHashMap

LinkedHashMap是HashMap的子类,它多了一对链表来维护添加元素顺序的顺序。

static class Entry<K,V> extends HashMap.Node<K,V> {
Entry<K,V> before, after;
Entry(int hash, K key, V value, Node<K,V> next) {
super(hash, key, value, next);
}
}

6.3.3 Map实现类之三:java.util.TreeMap

  • TreeMap存储 Key-Value 对时,需要根据 key-value 对进行排序。 TreeMap 可以保证所有的 Key-Value 对处于有序状态。
  • TreeSet底层使用红黑树结构存储数据
  • TreeMap 的 Key 的排序:
    • 自然排序:TreeMap 的所有的 Key 必须实现 Comparable 接口,而且所有的 Key 应该是同一个类的对象,否则将会抛出 ClasssCastException
    • 定制排序:创建 TreeMap 时,传入一个 Comparator 对象,该对象负责对TreeMap 中的所有 key 进行排序。此时不需要 Map 的 Key 实现Comparable 接口
  • TreeMap判断两个key相等的标准:两个key通过compareTo()方法或者compare()方法返回0

自然排序

class Person implements Comparable<Person>{
private String Name;
private int age;

//省略构造器、getter、setter、hashCode()、equals()、toString()....

@Override
public int compareTo(Person o) {
return this.age-o.age;
}

}
public class TestTreeMap {
@Test
public void test01(){
TreeMap<Person,String> treeMap = new TreeMap<>();
treeMap.put(new Person("Mike",30),"Boss");
treeMap.put(new Person("Jerry",18),"Student");
treeMap.put(new Person("Rose",24),"HouseWife");

System.out.println("自然排序:");
Set<Map.Entry<Person,String>> entrySet = treeMap.entrySet();
Iterator<Map.Entry<Person,String>> iterator = entrySet.iterator();
while(iterator.hasNext()){
Map.Entry<Person,String> entry = iterator.next();
System.out.println(entry.getKey()+" : "+entry.getValue());
}
}
}
/*Output:
自然排序:
Person{Name='Jerry', age=18} : Student
Person{Name='Rose', age=24} : HouseWife
Person{Name='Mike', age=30} : Boss
*/

定制排序

class Customer{
private String name;
private int age;

//省略构造器、getter、setter、hashCode()、equals()、toString()....
}

//Customer比较器
class CustomerComparator implements Comparator<Customer>{
@Override
public int compare(Customer o1, Customer o2) {
return o1.getAge()-o2.getAge();
}
}

public class TestTreeMap {
@Test
public void test02(){
TreeMap<Customer,String> treeMap = new TreeMap<>(new CustomerComparator());
// TreeMap<Customer,String> treeMap = new TreeMap<>((Customer o1,Customer o2)->o1.getAge()-o2.getAge());
treeMap.put(new Customer("Mike",30),"Boss");
treeMap.put(new Customer("Jerry",18),"Student");
treeMap.put(new Customer("Rose",24),"HouseWife");

System.out.println("定制排序:");
Set<Map.Entry<Customer,String>> entrySet = treeMap.entrySet();
Iterator<Map.Entry<Customer,String>> iterator = entrySet.iterator();
while(iterator.hasNext()){
Map.Entry<Customer,String> entry = iterator.next();
System.out.println(entry.getKey()+" : "+entry.getValue());
}
}
}
/*Output:
定制排序:
Customer{name='Jerry', age=18} : Student
Customer{name='Rose', age=24} : HouseWife
Customer{name='Mike', age=30} : Boss
*/

6.3.4 Map实现类之四:java.util.Hashtable

  • Hashtable是个古老的 Map 实现类,JDK1.0就提供了。不同于HashMap, Hashtable是线程安全的。
  • Hashtable实现原理和HashMap相同,功能相同。底层都使用哈希表结构,查询速度快,很多情况下可以互用。
  • 与HashMap不同,Hashtable 不允许使用 null 作为 key 和 value
  • 与HashMap一样,Hashtable 也不能保证其中 Key-Value 对的顺序
  • Hashtable判断两个key相等、两个value相等的标准,与HashMap一致。

6.3.5 Map实现类之五 java.util.Properties

  • Porperties是Hashtable的子类,常用来处理配置文件
  • 由于配置文件是文本,所有key和value都是字符串类型
  • 存取推荐方法:setProperties(String key,String value)和getProperties(String key)

创建一个Resource Bundle文件

写入内容

public class PropertiesTest {
public static void main(String[] args) {
Properties pros = new Properties();
try {
FileInputStream fis = new FileInputStream("jdbc.properties");
pros.load(fis);
System.out.println(pros.getProperty("name"));
System.out.println(pros.getProperty("password"));
fis.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/*
Tom
abc123
*/

7. Collections工具类

7.1 概述

  • Collections是一个可以操作Collection、Map的工具类
  • Collections工具类中提供对集合的排序、查询和修改等操作,还提供了对集合中元素不可变、对集合对象实现同步控制等方法

7.2 排序操作的方法

  • 排序操作:(均为static方法)
    • reverse(List):反转 List 中元素的顺序
    • shuffle(List):对 List 集合元素进行随机排序
    • sort(List):根据元素的自然顺序对指定 List 集合元素按升序排序
    • sort(List,Comparator):根据指定的 Comparator 产生的顺序对 List 集合元素进行排序
    • swap(List,int, int):将指定 list 集合中的 i 处元素和 j 处元素进行交换

7.3 查找、替换的方法

  • 查找、替换

    • <T extends Object & Comparable<? super T>> T max(Collection<? extends > coll):根据元素的自然顺序,返回给定集合中的最大元素
    • <T> T max(Collection<? extends T> coll, Comparator<? super T> comp) :根据 Comparator 指定的顺序,返回给定集合中的最大元素
    • <T extends Object & Comparable<? super T>> T min(Collection<? extends > coll)
    • <T> T min(Collection<? extends T> coll, Comparator<? super T> comp)
    • int frequency(Collection<?> c, Object o) :返回指定集合中指定元素的出现次数
    • <T> void copy(List<? super T> dest, List<? extends T> src) :将src中的内容复制到dest中
    @Test
    public void test02(){
    List<String> src = new ArrayList<>();
    src.add("Tom");
    src.add("Jack");
    src.add("Lili");

    List<String> dest = new ArrayList<>();
    //Collections.copy(dest, src);
    //报错
    System.out.println(dest);
    }

    上述代码会报一个错误:Source does not fit in dest,原因是因为在copy中

    int srcSize = src.size();
    if (srcSize > dest.size())
    throw new IndexOutOfBoundsException("Source does not fit in dest");

    可知src的长度要小于或等于要赋值到的dest,下面是对dest代码的改造

    @Test
    public void test02(){
    List<String> src = new ArrayList<>();
    src.add("Tom");
    src.add("Jack");
    src.add("Lili");

    //填充dest
    List<String> dest = Arrays.asList(new String[src.size()]);
    Collections.copy(dest, src);
    System.out.println(dest);
    /*Output
    [Tom, Jack, Lili]
    */
    }
    • <T> boolean replaceAll(List<T> list, T oldVal, T newVal) :使用新值替换List 对象的所有旧值

7.4 同步控制的方法

  • Collections中提供synchronizedXxx()方法,这些方法可将指定集合包装成线程同步的集合,从而可以解决多线程并发访问集合时的线程安全问题
Modifier and TypeMethod and Description
static <T> Collection<T>synchronizedCollection(Collection<T> c)
Returns a synchronized (thread-safe) collection backed by the specified collection.
static <T> List<T>synchronizedList(List<T> list)
Returns a synchronized (thread-safe) list backed by the specified list.
static <K,V> Map<K,V>synchronizedMap(Map<K,V> m)
Returns a synchronized (thread-safe) map backed by the specified map.
static <K,V> NavigableMap<K,V>synchronizedNavigableMap(NavigableMap<K,V> m)
Returns a synchronized (thread-safe) navigable map backed by the specified navigable map.
static <T> NavigableSet<T>synchronizedNavigableSet(NavigableSet<T> s)
Returns a synchronized (thread-safe) navigable set backed by the specified navigable set.
static <T> Set<T>synchronizedSet(Set<T> s)
Returns a synchronized (thread-safe) set backed by the specified set.
static <K,V> SortedMap<K,V>synchronizedSortedMap(SortedMap<K,V> m)
Returns a synchronized (thread-safe) sorted map backed by the specified sorted map.
static <T> SortedSet<T>synchronizedSortedSet(SortedSet<T> s)
Returns a synchronized (thread-safe) sorted set backed by the specified sorted set.

总结点

Collection接口中的Vector类和Map接口中的Hashtable类都是从JDK1.0开始的,并且都是线程安全但效率不高,目前常用ArrayList类和HashMap类,如果要实现线程安全也不用Vector和Hashtable,而是使用Collections工具类

面试题

  1. ArrayList、LinkedList、Vector三者的异同

    • 相同点
      • 实现来源相同:都实现了List接口
      • 存储特点相同:有序、可重复
    • 不同点
      • 底层实现不同
        • ArrayList、Vector底层为数组
        • LinkedList底层为双向链表
      • 线程安全性问题
        • ArrayList、LinkedList线程不安全
        • Vector线程安全
      • 扩容机制
        • ArrayList:1.5倍
        • Vector:2倍
      • 增删查效率不同
        • ArrayList、Vector查询效率高
        • LinkedList增删效率高
  2. HashMap的底层实现原理?

  3. HashMap和Hashtable的异同?

  • 相同点
    • 父接口相同:都是实现了Map接口
    • 存储结构相同:都是以键值对的方式存储
  • 不同点
    • 底层实现不同
      • HashMap在JDK1.8之后是数组+链表+红黑树
      • LinkedHashMap除了HashMap结构外,还有一对指针来维护其添加的顺序
    • 增删效率不同
      • HashMap增删效率低
      • LinkedHashMap增删效率高
    • 线程安全性不同
      • HashMap线程不安全
      • Hashtable线程安全
  1. CurrentHashMap和Hashtable的区别?

  2. Collection和Collections的区别?