Java集合的简单理解
  BA7aR24amlGh 2023年11月02日 48 0

集合

集合框架概述

集合和数组都是对多个数据进行存储操作的结构,也就是容器。此时存储的主要是内存层次的存储,也就是临时容器,而不是向数据库或者文件那种持久化的容器。而Java中的集合就是一种很好的临时容器,可以动态的把多个对象放入到容器中。
此前用到的数组也可以保存数据,但是数组的缺点也很多:

  1. 长度在开始时必须指定,一旦指定不能更改。
  2. 保存的数据必须为同一类型的元素。
  3. 使用数组进行添加、删除、插入等操作比较麻烦。
  4. 数组存储数据是有序、可重复的,不能存储无序不可重复的需求。

集合却没有这些问题:

  1. 可以动态保存任意多个对象,使用比较方便!
  2. 提供了一系列方便的操作对象的方法:add、remove、set、get等。
  3. 使用集合添加,删除新元素比较简单。

集合框架体系

Java集合的集合类很多,主要分为两大类(单列集合和双列集合):

4. Collection接口:单列集合,用来存储一个一个的对象。又分为List和Set。

5. Map接口:双列集合、用来存储一对一对的数据。

迭代器

基本介绍

  1. Iterator对象称为迭代器,主要用于遍历Collection集合中的的元素。
  2. 所有实现了Collection接口的集合类都有一个iterator()方法,用以返回一个实现了Iterator接口的对象,即可以返回一个迭代器。
  3. Iterator仅用于遍历集合,Iterator本身并不存放对象。

迭代器执行原理

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * @author Wen先森
 * @version 1.0
 * @date 2022/3/29 17:05
 */
public class Demo03 {
    public static void main(String[] args) {
        List list = new ArrayList();
        list.add(1);
        list.add(2);
        list.add(3);//创建一个集合并添加数据
        Iterator iterator =list.iterator();//得到一个集合的迭代器
        while (iterator.hasNext()){//hasNext():判断是否还有下一个元素
            System.out.println(iterator.next());//next():作用是下移并且将下移以后集合位置上的元素返回。
        }
    }
}

Java集合的简单理解_集合

在调用iterator.next()方法之前必须要调用iterator.hasnext()检测判断是否还有下一个元素,如果不调用,且没有下一条元素,则调用iterator.next()会抛出异常。

Collection接口

  1. Collection实现子类可以存放多个元素,每个元素可以是Object。
  2. 有些Collection的实现类,可以存放重复的元素,有些不可以。
  3. 有些Collection的实现类,有些是有序的(List),有些是无序的(Set)。
  4. Collection接口没有直接的实现子类,是通过它的子接口Set和List来实现的。

Collection接口常用方法:

常用方法名

方法说明

add();

添加单个元素

remove();

删除指定元素

contains();

查找元素是否存在

size();

获取元素个数

isEmpty();

判断是否为空

clear();

清空

addAll();

添加多个元素

removeAll();

删除多个元素

ContainsAll();

查找多个元素

List接口

List接口是Collection接口的子接口

  1. List集合类中的元素时有序的(即添加顺序和取出顺序是一致的)、且可重复。
  2. List集合中的每个元素都有其对应的顺序索引,即支持索引。
  3. List容器中的元素都对应一个整数型的序号记载其在容器中的位置,可以根据序号存取容器中的元素。
  4. List接口所有已知实现类:AbstractList, AbstractSequentialList, ArrayList, AttributeList, CopyOnWriteArrayList, LinkedList, RoleList, RoleUnresolvedList, Stack, Vector
  5. List接口常用实现类:ArrayList、LinkedList、Vector。

Java集合的简单理解_数组_02

List接口常用方法:

常用方法名

方法说明

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(不包含toIndex)位置的子集合

List三种遍历方式

1.迭代器遍历Iterator iterator=list.iterator();while (iterator.hasNext()) { Object next = iterator.next(); System.out.println(next); }

2.增强for循环

for (Object obj :list) { System.out.println(obj);}

3.普通for循环

for (int i = 0; i < list.size(); i++) { Object obj=list.get(i); System.out.println(obj); }

 ArrayList实现类底层结构

ArrayList注意事项:

  1. ArrayList可以加入null,并且多个也可以。
  2. ArrayList是由数组来实现数据存储的。
  3. ArrayList基本等同于Vector。除了ArrayList是线程不安全的,在多线情况下,不建议使用ArrayList。

ArrayList扩容机制:

  1. ArrayList中维护了一个Object类型的数组elementData。即:transient Object [] elementData ; //transient表示瞬间,短暂的,表示属性不会被序列化
  2. 当创建ArrayList对象时,如果使用的是无参构造器,则初始elementData容量为0,第一次添加,则扩容elementData为10,如果需要再次扩容,则扩容elementData为1.5倍。
  3. 如果使用的是指定大小的构造器,则初始elementData容量为指定大小,如果需要扩容,则扩容elementData为1.5倍。

分析使用无参构造器,创建和使用ArrayList的源码:

//创建一个空的elementData数组={}
public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
//执行list.add
//先确认是否需要扩容,
//然后再执行赋值
public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
}
//该方法确定minCapacity
//第一次扩容为10
private static int calculateCapacity(Object[] elementData, int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            return Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        return minCapacity;
}
//mouCount++记录集合被修改的次数
//如果elementData的大小不够,则调用grow()扩容
private void ensureExplicitCapacity(int minCapacity) {
        modCount++;

        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
}
//调用grow()扩容
//第一次扩容newCpacity=10
//第二次及以后,按照之前大小的1.5倍扩容
//扩容使用的是Arrays.copy()
private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1); //oldCapacity >> 1相当于/2
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        // minCapacity is usually close to size, so this is a win:
        elementData = Arrays.copyOf(elementData, newCapacity);
}

Java集合的简单理解_数组_03

 使用有参构造器,创建使用ArrayList源码:

//创建一个指定大小的elementData数组
//大小大于0时, this.elementData = new Object[initialCapacity];
//等于0时,相当于无参构造器,创建一个空数组。
public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) {
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
}

Java集合的简单理解_ci_04

如果是有参数的构造器,扩容机制:

  1. 第一次扩容,就按照elementData的1.5倍扩容。
  2. 整个执行流程还是和无参的一样。

Vector实现类底层结构

  1. Vector底层也是一个对象数组,protected Object[] elementData;
  2. Vector是线程同步的,即线程安全,Vector类的操作方法带有synchronized同步锁。
  3. 在开发中,需要线程同步安全时,考虑使用Vector。

ArrayList和Vector的比较

实现类

底层结构

版本

线程安全(同步)效率

扩容倍数

ArrayList

可变数组

jdk1.2

不安全,效率高

1.如果有参构造扩容按照1.5倍

2.如果是无参,第一次10,第二次开始同样按照1.5倍扩容

Vector

可变数组

Jdk1.0

安全,效率不高

1.有参指定大小,则每次扩容按照2倍

2.如果是无参,第一次10,第二次开始同样按照2倍扩容

 LinkedList底层结构

  1. LinkedList底层实现了双向链表和双端队列特点。
  2. 可以添加任何元素(元素可以重复),包括null。
  3. 线程不安全,没有实现同步。
  4. LinkedList中维护了两个属性first和last分别指向首节点和尾节点。
  5. 每个节点(Node对象),里面有维护了pre,next,item三个属性,其中通过pre指向前一个结点,通过next指向后一个节点。最终实现双向链表。
  6. LinkedList的元素的添加和删除,不是通过数组完成的,相对来说效率较高。
  7. 模拟一个简单的双向链表如下代码:
package com.study.srv.demo13;

/**
 * @author Wen先森
 * @version 1.0
 * @date 2022/3/31 14:43
 */
public class Demo11 {
    public static void main(String[] args) {
        Node jack = new Node("jack");
        Node tom = new Node("tom");
        Node rose = new Node("rose");
        jack.next=tom;
        tom.next=rose;
        rose.pre=tom;
        tom.pre=jack;
        Node first=jack;
        Node end=rose;
        while (true){
            if (first==null){
                break;
            }
            System.out.println(first);
            first=first.next;
        }
        System.out.println("插入一个bob");
        Node bob = new Node("bob");
        tom.next=bob;
        bob.next=rose;
        rose.pre=bob;
        bob.pre=tom;
        while (true){
            if (end==null){
                break;
            }
            System.out.println(end);
            end=end.pre;
        }
    }
}
class Node{
    public String item;
    public Node pre;
    public Node next;

    public Node(String item) {
        this.item = item;
    }

    @Override
    public String toString() {
        return "Node{" +
                "item='" + item + '\'' +
                '}';
    }
}

Java集合的简单理解_ci_05

ArrayList和LinkedList比较

List实现类

底层结构

增删的效率

改查的效率

ArrayList

可变数组

较低,数组扩容

较高

LinkedList

双向链表

较高,通过链表追加

较低

如何选择ArrayList和LinkedList:

  1. 如果我们改查的操作多,选择ArrayList。
  2. 如果我们增删的操作多,选择LinkedList.
  3. 一般来说,在项目中,80%-90%都是查询,因此大部分选择ArrayList
  4. 在一个项目中,根据业务灵活选择,也只能这样,一个模块使用的是ArrayList,另一个模块是LinkedList,也就是根据业务来进行选择。

Set接口

  • Set接口也是Collection接口的子接口。
  1. Set集合类的元素是无序的(添加和取出的顺序不一致),没有索引。但是LinkedHashSet可以保证元素添加的顺序,TreeSet保证元素自然的顺序。
  2. 不允许重复元素,所以最多只包含一个null。
  3. Set接口所有已知实现类:AbstractSet, ConcurrentSkipListSet, CopyOnWriteArraySet, EnumSet, HashSet, JobStateReasons, LinkedHashSet, TreeSet 
  4. Set接口常用实现类:HashSet、TreeSet。 
  •  Set接口常用方法

        跟List接口一样,Set接口也是Collection接口的子接口,因此常用方法和Collection接口一样。

  • Set接口的遍历方式
  1. 可以使用迭代器
  2. 增强for循环
  3. 不能使用索引的方式来获取。

HashSet实现类

  • HashSet实现了Set接口。
  • HashSet实际上是HashMap。

public HashSet() { map = new HashMap<>();}

  • HashSet可以存放null值,但是只能存在一个
  • HashSet不保证元素是有序的,取决于Hash后,再确定索引的结果(即,不保证存放元素的顺序和取出顺序一致)
  • 不能有重复数据/对象。 

 HashSet底层是HashMap,HashMap底层是(数组+链表+红黑树)。

Java集合的简单理解_java_06

HashSet添加元素底层实现:

  1. HashSet底层是HashMap
  2. 添加一个元素时,先得到hash值,hash值会转换为索引值。
  3. 找到储存数据表table,看这个索引位置是否已经有存放的元素。
  4. 如果没有,直接加入。
  5. 如果有就用eqlus比较,如果相同就放弃添加,如果不同添加到最后。
  6. 在Java8中,如果一条链表的元素个数到达TREEIFY_THRESHOLD(默认是8),并且table的大小>=MIN_TREEIFY_CAPACITY(64)就会进行树化(红黑树)。

HashSet扩容和转成红黑树机制:

  1. HashSet底层是HashMap,第一次添加时,table数组扩容到16,临界值(threshold)是16*加载因子(loadFactor)是0.75=12.
  2. 如果table数组使用到了临界值12,就会扩容到16*2=32,新的临界值就是32*0.75=24,以此类推。
  3. 在Java8中,如果一条链表的元素个数到达TREEIFY_THRESHOLD(默认是8),并且table的大小>=MIN_TREEIFY_CAPACITY(64)就会进行树化(红黑树)。

LinkedHashSet实现类

  1. LinkedHashSet是HashSet的子类,也是Set接口的实现类。
  2. LinkedHashSet底层是一个LinkedHashMap,底层维护了一个数组+双向链表
  3. LinkedHashSet根据元素的hashCode值来决定元素的存储位置,同时使用链表维护元素的次序,这使得元素看起来是以插入顺序保存的。
  4. LinkedHashSet不允许添加重复元素。

Java集合的简单理解_java_07

Set set=new LinkedHashSet();set.add(new String("A"));set.add("Q");set.add("Q");set.add(new Customer("西",101)); set.add(1); set.add("H");

说明:

  1. 在LinkedHashSet 中维护了哟个hash表和双向链表(LinkedHashSet 中有head和tail)
  2. 每一个节点有before和after属性,这样可以形成双向链表。
  3. 在添加一个元素时,先求hash值,再求索引,确定该元素在table中的位置,然后将添加的元素加入到双向链表中(如果已经存在,不添加【原则上跟HashSet一样】)。
  1.  tail.next=newElement;
  2. newElement.pre=tail;
  3. tail=newElement;
  1. 这样的话,我们遍历LinkedHashSet也能确保插入顺序和遍历顺序是一致的。

TreeSet实现类

  1. TreeSet添加数据时,只能添加一种数据类型的数据。
  2. 使用treeSet集合存储自定义对象,无参构造器方法是通过自然排序对元素进行排序的。
  3. 自然排序就是让元素所属的类实现Comparable接口,重写compareTo()方法。
  4. Integer能排序(有默认排序),String能排序(有默认排序),自定义的类存储的时候出现异常(因为没有默认排序) 。
  5. TreeSet是依靠Treemap实现的,TreeSet是一个有序不可重复集合。TreeSet中的元素将按照升序排列,缺省是按照自然排序进行排列,意味着TreeSet中的元素要实现Comparable接口,或者自定义的比较器。
package com.study.srv.demo14;

import java.util.TreeSet;

/**
 * @author Wen先森
 * @version 1.0
 * @date 2022/4/8 10:05
 */
public class Demo07 {
    public static void main(String[] args) {
        TreeSet treeSet=new TreeSet();
        treeSet.add(1);
//        treeSet.add("2");//treeSet只能添加一种类型的数据
        treeSet.add(2);
        treeSet.add(4);
        treeSet.add(3);
        treeSet.add(0);
        System.out.println(treeSet);
        TreeSet set=new TreeSet();
        set.add("Alen");
        set.add("Ben");
        set.add("Jack");
        set.add("Hlean");
        System.out.println(set);
        TreeSet set1=new TreeSet();
        set1.add(new Son("jack",22));
        set1.add(new Son("Mark",19));
        set1.add(new Son("Alen",26));
        set1.add(new Son("Cily",20));
        System.out.println(set1);
    }
}

Java集合的简单理解_集合_08

class Son {
    private String name;
    private int age;

    public Son(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 String toString() {
        return "Son{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
    
}

 解决方案:

  • Son类实现Comparable接口
  • 重写 compareTo(Object o)方法
class Son implements Comparable{
    private String name;
    private int age;

    public Son(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 String toString() {
        return "Son{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    @Override
    public int compareTo(Object o) {
        Son son=(Son)o;
        int num=this.age>son.age ?1:(this.age==son.age ? 0:-1);//升序
        //int num=this.age<son.age ?1:(this.age==son.age ? 0:-1); //降序
        if (num==0){
            num=this.name.compareTo(son.name); //当age一样时,根据name比较排序
        }
        return num;
    }
}

Java集合的简单理解_数组_09

Java集合的简单理解_ci_10

 也可以使用TreeSet的另一个构造器,即传入一个比较器(用匿名内部类)

package com.study.srv.demo14;

import java.util.Comparator;
import java.util.TreeSet;

/**
 * @author Wen先森
 * @version 1.0
 * @date 2022/4/8 10:50
 */
public class Demo08 {
    public static void main(String[] args) {
        TreeSet set=new TreeSet(new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                Son1 son1=(Son1) o1;
                Son1 son2=(Son1) o2;
                int result =son1.getAge()>son2.getAge()?1 :(son1.getAge()==son2.getAge()?0:-1);
                if (result==0){
                    result=son1.getName().compareTo(son2.getName());
                }
                return result;
            }
        });
        set.add(new Son1("jack",22));
        set.add(new Son1("Mark",19));
        set.add(new Son1("Alen",26));
        set.add(new Son1("Cily",22));
        System.out.println(set);
    }
}
class Son1  {
    private String name;
    private int age;

    public Son1(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 String toString() {
        return "Son{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

Java集合的简单理解_集合_11

HashSet和TreeSet的去重机制 

  1. HashSet的去重机制:hashCode()+equals(),底层先通过存入对象,进行运算得到一个flash值,通过hash值得到对应的索引,如果发现table索引所在的位置,没有数据,就直接存放如果有数据,就进行equals比较[遍历比较],如果比较后,不相同,就加入,否则就不加入。
  2. TreeSet的去重机制:如果你传入了一个Comparator 匿名对象,就使用实现的compare去重,如果方法返回0.就认为是相同的元素/数据,就不添加,如果你没有传入一个 Comparator 匿名对象,则以你添加的对象实现的 Compareable 接口的compareTo去重.

 Map接口

Map接口特点

JDK8的Map接口特点:

  1. Map与Collection并列存在。用于保存具有映射关系的数据:Key-Value(双列元素)。
  2. Map中的key和value可以是任何引用类型的数据,会封装到HashMao$Node对象中。
  3. Map中的key不允许重复,原因和HashSet一样。当有相同的key时,就等价于替换。
  4. Map中的value可以重复。
  5. Map中的key可以为null,value也可以为null,但要注意key中的null只能有一个,values中的null可以有多个。
  6. 常用String类作为Map的key,但并不代表只能用String类型的,只要是Object子类就可以用。
  7. key和value之间存在单向一对一关系,即通过指定的key总能找到对应的value。
  8. Map存放数据的key-value示意图,一对k-v是放在Node中的,因为Node实现了Entry接口,有些书也说一对k-v就是一个Entry。 

Java集合的简单理解_java_12

Java集合的简单理解_数组_13编辑

containsKey:查找键是否存在。

keySet:获取所有的键。

entrySet:获取所有关系k-v。

values:获取所有值。

Map接口常用方法

方法名

方法说明

put()

添加元素

remove()

根据键删除映射关系

get()

根据键获取值

size()

获取元素个数

isEmpty

判断个数是否为0

clear()

清除

containsKey

查找键是否存在

Map map=new HashMap();
        //put添加
        map.put("张翠山","殷素素");
        map.put("张无忌","赵敏");
        map.put("郭靖","黄蓉");
        map.put("杨过","小龙女");
        map.put("张无忌","周芷若");
        System.out.println(map);
        //remove 根据键删除映射关系
        map.remove("张无忌");
        System.out.println(map);
        //get 根据键获取值
        map.get("杨过");
        System.out.println(map);
        //size 获取元素个数
        System.out.println(map.size());
        //isEmpty 判断元素个数是否为0
        System.out.println(map.isEmpty());
        //clear 清除
        map.clear();
        System.out.println(map);
        //containsKey 查找键是否存在
        System.out.println(map.containsKey("杨过"));

Java集合的简单理解_集合_14

 Map接口遍历方式

根据keySet获取所有键遍历:

//根据keySet获取所有键根据键遍历
        Set keySet = map.keySet();
        //强循环
        System.out.println("keySet强循环:");
        for (Object key :keySet) {
            System.out.println(key+"="+map.get(key));
        }
        //迭代器
        System.out.println("keySet迭代器");
        Iterator iterator=keySet.iterator();
        while (iterator.hasNext()){
            Object key=iterator.next();
            System.out.println(key+"="+map.get(key));
        }

Java集合的简单理解_java_15

根据value遍历:

//找到所有的value,根据value遍历
        Collection values=map.values();
        //增强for循环
        System.out.println("Values强循环:");
        for (Object value:values) {
            System.out.println(value);
        }
        //迭代器
        System.out.println("Values迭代器");
        Iterator iterator1=values.iterator();
        while (iterator1.hasNext()) {
            Object next = iterator1.next();
            System.out.println(next);
        }

根据entrySet所有关系k-v遍历:

//可以获取所有的键映射,之后遍历
        Set entrySet=map.entrySet();
        //增强for循环
        System.out.println("entrySet强循环:");
        for (Object entry:entrySet) {
            Map.Entry m=(Map.Entry)entry;
            System.out.println(m.getKey()+"="+m.getValue());
        }
        //迭代器
        System.out.println("entrySet迭代器");
        Iterator iterator2=entrySet.iterator();
        while (iterator2.hasNext()) {
            Object next = iterator2.next();
            Map.Entry m=(Map.Entry)next;
            System.out.println(m.getKey()+"="+m.getValue());
        }

Java集合的简单理解_集合_16

HashMap实现类

  1. Map接口的常用实现类:HashMap、HashTable和Properties。
  2. HashMap是Map接口使用频率最高的实现类。
  3. HashMap是以key-value对的方式来存储数据。
  4. key不能重复,但是value值可以重复,允许使用null键和null值。
  5. 如果添加相同的key,则会覆盖原来的key-val,等同于修改(不同的是,key不会替换,会替换val)。
  6. 与HashSet一样,不保证映射顺序,因为底层都是以hash表方式存储的。
  7. HashMap没有实现同步(方法没有互斥操作),因此线程不安全。

HashMap扩容机制

  1. HashMap底层维护了Node类型的数组table,默认为null。
  2. 当创建对象时 ,将加载因子(loadfactor)初始化为0.75。
  3. 当添加key-val时,通过key的hash值得到在table数组中的索引。然后判断该索引是否存在元素,如果没有元素直接添加。如果该处索引有元素,继续判断该元素的key是否和准备加入的key相等,如果相等,直接替换val;如果不相等需要判断是树结构还是链表结构,做出相应处理。如果容量不够,则需要扩容。
  4. 第一次添加,需要扩容table容量为16,临界值(threshold)为12.
  5. 以后再次扩容,则需要扩容table容量为原来的两倍,临界值为原来的2被,即24,以此类推。
  6. 在java8中,如果一条链表的元素个数超过TREEIFY_THRESHOLD(默认是8),并且table的大小>=MIN_TREEIFY_CAPACITY(默认64),就会进行树化(红黑树)。

HashTable 实现类

  1. 存放的元素是键值对:即k-v。
  2. hashtable的键与值都不能为null。
  3. hashtable使用方法基本和hashmap一样。
  4. HashTable是线程安全的,HashMap是线程不安全的。

HashTable扩容机制

  1. Hashtable的扩容机制通过rehash()来实现,数组长度初始为11个,如果Hashtable中元素的个数大于临界值时,会调用rehash()来实现扩容。临界值的大小等于Hashtable数组的大小与负载因子相乘,默认的负载因子大小为0.75。
  2. Hashtable扩容的数组长度是旧数组长度乘以2加1 。
  3. Hashtable采用头插法的方式迁移数组。

HashMap与HashTable对比

实现类

版本

线程安全(同步)

效率

允许null键null值

HashMap

1.2

不安全


可以

HashTable

1.0

安全

较低

不可以

Properties实现类

  1. Properties类继承自HashTable类且实现了Map接口,也是使用一种键值对的形式来保存数据。
  2. 使用特点与HashTable类似。
  3. Properties还可以用于从XXX.properties文件中,加载数据到Properties类对象,并进行读取和修改。
  4. XXX.properties文件中通常用做配置文件。

TreeMap

  1. TreeMap 存储key-val键值对,底层通过红黑树实现。
  2. TreeMap与TreeSet一样,都有默认的自然排序。
  3. 与HashMap相比,TreeMap是一个能比较元素大小的Map集合,会对传入的key进行大小排序,其中可以使用元素的自然排序,也可以使用集合中自定义的比较器来进行定义。
  4. 不允许插入重复的key。
  5. 可以插入null键、null值。
  6. 可以对元素进行排序,但是它是无序集合(插入和遍历顺序不一样)。

 总结——选择集合实现类

在开发中,选择什么集合实现类,主要取决于业务操作特点,然后根据集合实现特性进行选择。

  1. 先判断存储的类型(一组对象【单列】或一组键值对【双列】)。
  2. 一组对象【单列】:Collection接口
  1. 允许重复:list
  1. 增删多:LinkedList【底层维护了一个双向链表】。
  2. 改查多:ArrayList【底层维护了Object类型的可变数组】。
  1. 不允许重复:Set
  1. 无序:HashSet【底层是HashMap,维护了一个哈希表,数组+链表+红黑树】。
  2. 排序:TreeSet
  3. 插入顺序和取出顺序一致:LinkedHashSet【底层维护数组+双向链表】。
  1. 键无序:HashMap【底层维护时哈希表,数组+链表+红黑树】。
  2. 键排序:TreeMap
  3. 键插入顺序和取出顺序一致:LindedHashMap。
  4. 读取文件:Properties。

Collections工具类

  1. Collections是一个操作List、Set和Map等集合的工具类。
  2. Collections中提供了一系列的静态方法对集合元素进行排序、修改和删除操作。

排序操作

方法说明

reverse(List)

翻转List集合中元素的顺序

shuffle(List)

对List集合元素进行随机排序

sort(List)

根据元素的自然顺序对指定的List集合元素按升序排列

sort(List,Comparator)

根据指定的Comparator产生的顺序对List集合进行排序

swap(List,int,int)

将指定List集合中的i处元素和j处元素进行交换

查找、替换操作

方法说明

Object max(Collection);

根据元素的自然排序,返回给定集合中的最大值。

Object max(Collection,Comparator);

根据指定的Comparator产生的顺序,返回给定集合中的最大值。

Object min(Collection);

根据元素的自然排序,返回给定集合中的最小值。

Object min(Collection,Comparator);

根据指定的Comparator产生的顺序,返回给定集合中的最小值。

int frequency(Collection,Object);

返回指定集合中指定元素的出现次数

void copy(List dest,List src);

将src中的内容复制到dest中

boolean replaceAll(List list,Object oldVal,Object newVal);

使用新值替换List对象的所有值

 特别注意的是:void copy(List dest,List src);中dest的集合大小一定不能小于src集合的大小否则报IndexOutOfBoundsException异常。


【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月08日 0

暂无评论

推荐阅读
  2Vtxr3XfwhHq   2024年05月17日   53   0   0 Java
  Tnh5bgG19sRf   2024年05月20日   107   0   0 Java
  8s1LUHPryisj   2024年05月17日   46   0   0 Java
  aRSRdgycpgWt   2024年05月17日   47   0   0 Java
BA7aR24amlGh