Java容器类

Java 容器类

1. Java 中的常见容器类

img

1.1 几种常见的集合类及特点

常见的集合类: ArrayList,LinkedList,Vector,HashSet, TreeSet,HashMap , HashTable

list 中的元素可重复,set ,map 中的元素不可重复。

1.1.1 List

List:

  • ArrayList 底层结构是数组,底层查询快,增删慢。

    ArrayList:基于数组实现,非线程安全的,效率高,便于索引,但不 便于插入删除;数组是空间连续的内存空间,每次在做数据的插入和删除,涉及到其他元素的移动,所以效率较慢;

  • LinkedList 底层结构是链表型的,增删快,查询慢。

    LinkedList:基于链表实现,链表内存是散乱的,每一个元素存储本身内存地址的同时还 存储下一个元素的地址。链表增删快,查找慢;

  • voctor 底层结构是数组 线程安全的,增删慢,查询慢

    Vector:基于数组实现,线程安全的,效率低

1.1.2 Map

Map 接口有三个实现类(HashMap:基于 hash 表的 Map 接口实现,非线程安全,高效,支持 null 值和 null 键;HashTable:线程安全,低效,不支持 null 值和 null 键;LinkedHashMap:是 HashMap 的一个子类,保存了 记录的插入顺序;SortMap 接口:TreeMap,能够把它保存的记录根据键排序,默认是键值的升序排序)。

1.1.3 Set

Set 接口有两个实现类(HashSet:底层是由 HashMap 实现,不允许集合中有重复的值,使用该方式时需要重 写 equals()和 hashCode()方法;LinkedHashSet:继承与 HashSet,同时又基于 LinkedHashMap 来进行实现,底 层使用的是 LinkedHashMp)。

1.1.4 List,Set,Map 间的差异性对比

  1. List 和 Set 是存储单列数据的集合,Map 是存储键和值这样的双列数据的集合;

  2. List 中存储的数据是有顺序,并且允许重复;Map 中存储的数据是没有顺序的,其键是不能重复的,它的值是可以有重复的,Set 中存储的数据是无序的,且不允许有重复,但元素在集合中的位置由元素的 hashcode 决定,位置是固定的

    (Set 集合根据 hashcode 来进行数据的存储,所以位置是固定的,但是位置不是用户可以控制的,所以对于用户来说 set 中的元素还是无序的);

比较ListSetMap
继承接口CollectionCollection
常见实现类ArrayList,LinkedList,VectorHashSet,LinkedHashSet,TreeSetHashMap,HashTable ,TreeMap,LinkedHashMap
是否可重复可重复不可重复不可重复
顺序有序无序(由HashCode决定数据位置),LinkedHashSet底层是链表加哈希表。是有序的。hashMap 是无序的,(由HashCode决定数据位置)。LinkedHashMap 是有序的

1.1.5 HashSet 和 HashMap

hashSet 的 底层是由 hashMap 实现的,HashSet 的值存放在 HashMap 的key 上,HashMap 的 value 统一是一个常量PRESENT。

1.1.6 ArrayList 和 LinkedList 的区别

ArrayList 的底层是数组,支持随机访问,LinkedList 的底层是双向循环链表,不支持随机访问。

1.1.7 Array 和 ArrayList 的区别

Array 只能存纳 基本数据类型的数据, 而ArrayList 只能容纳对象。

1.1.8 HashMap 和 HashTable 的区别

HashMap 是线程不安全的,HashMap 是一个接口( Map 的一个子接口),是将键映射到值得对象,不允许键值重复允许空键和空值;由于非线程安全,HashMap 的效率要较 HashTable 的效率高一些。
HashTable 是线程安全的一个集合,不允许 null 值作为一个 key 值或者 Value 值; HashTable中所有的方法都被synchronized关键字 修饰,多个线程访问时不需要自己为它的方法实现同步,而 HashMap 在被多个线程访问的时 候需要自己为它的方法实现同步;

2. 容器类的扩容

Class初始大小加载因子扩容倍数底层实现Code是否线程安全同步方式
ArrayList1011.5倍Object数组int newCapacity = oldCapacity + (oldCapacity >> 1); ">>"右移符号,所以是除以2,所以新的容量是就的1.5倍 Arrays.copyOf 调用 System.arraycopy 扩充数组线程不安全-
Vector1012倍Object数组int newCapacity = oldCapacity + ((capacityIncrement > 0) ? capacityIncrement : oldCapacity); capacityIncrement默认为0,所以是加上本身,也就是2*oldCapacity,2倍大小 Arrays.copyOf 调用 System.arraycopy 扩充数组线程安全synchronized
HashSet160.75f2倍HashMap<E,Object>add方法实际调用HashMap的方法put线程不安全-
HashMap160.75f2倍Map.Entryvoid addEntry(int hash, K key, V value, int bucketIndex) { if ((size >= threshold) && (null != table[bucketIndex])) { resize(2 * table.length); hash = (null != key) ? hash(key) : 0; bucketIndex = indexFor(hash, table.length); } createEntry(hash, key, value, bucketIndex); }线程不安全-
Hashtable110.75f2倍+1Hashtable.Entry数组int newCapacity = (oldCapacity << 1) + 1; if (newCapacity - MAX_ARRAY_SIZE > 0) { if (oldCapacity == MAX_ARRAY_SIZE) return; newCapacity = MAX_ARRAY_SIZE; }线程安全synchronized

3. 如何实现对HashMap的排序

实现对HashMap排序(hashMap 是无序的,子类linkedHashMap是有序的)

import java.util.*;
import java.util.stream.Collectors;

public class VolatileDemo {

    public static int num = 0;

    public static void main(String[] args) {
        HashMap<Integer, User> users = new HashMap<>();
        users.put(1, new User("张三", 25));
        users.put(3, new User("李四", 22));
        users.put(2, new User("王五", 28));

        HashMap sortMap = sortHashMap(users);

    }

    private static HashMap sortHashMap(HashMap<Integer, User> users) {
        HashMap sortMap = new LinkedHashMap<Integer,User>();
        Set<Map.Entry<Integer, User>> set = users.entrySet();
        ArrayList<Map.Entry<Integer, User>> entries = new ArrayList<>(set);
        Collections.sort(entries, (o1,o2)->{
            return o1.getValue().getAge() - o2.getValue().getAge();
        });
        entries.forEach((o)->{sortMap.put(o.getKey(),o.getValue());});

        Map<Integer, User> collect = entries.stream().collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

        Map<Integer, User> sortMap1 = set.stream().sorted((o1, o2) -> {
            return o1.getValue().getAge() - o2.getValue().getAge();
        }).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

        System.out.println(collect); 
        System.out.println(sortMap); //正确排序
        System.out.println(sortMap1);

        return sortMap;
    }
}

class User{
    private int age;
    private String name ;

    public User(String name, int age) {
        this.age = age;
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String naem) {
        this.name = naem;
    }

    @Override
    public String toString() {
        return "User{" +
                "age=" + age +
                ", name='" + name + '\'' +
                '}';
    }
}

4. ConcurrentHashMap

4.1 HashMap 和 ConcurrentHashMap 的区别

ConcurrentHashMap是线程安全的HashMap的实现。

  1. ConcurrentHashMap对整个桶数组进行了分割分段(Segment),然后在每一个分段上 都用lock锁进行保护,相对于HashTable的syn关键字锁的粒度更精细了一些,并发性能更 好,而HashMap没有锁机制,不是线程安全的。
  2. HashMap的键值对允许有null,但是ConCurrentHashMap都不允许。

5. HashTable

5.1 线程安全类的安全性分析

Hashtable 线程安全方法组合分析

线程安全类中的每个方法都能保证线程安全,但是线程安全方法的组合并不一定能够保证线程安全

Hashtable table = new Hashtable();
if(table.get("key") == null){
    table.put("key",value);
}

在这里插入图片描述

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

王叮咚

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值