Java集合详解list set map(最全)

集合详解(最全)

对各种Java集合做出解释整理主要有一下四种进行

是否线程安全

是否有序

是否是否唯一

是否为空

List:

ArrayList

查询快增删慢线

程不安全 效率高

有序

不唯一

可以为空

LinkedList

查询慢,增删快。

线程不安全,效率高

不唯一

可以为空

有序

Vector

Set:

HashSet

线程不安全

无序

唯一

不为空

LinkedHashSet

线程不安全

有序

唯一

可以为空

TreeSet

线程不安全

有序

唯一

不为空

Map:

HashMap

线程不安全

无序序

唯一

只有一个null

HashTable

线程安全

无序

唯一

不为空

TreeMap

线程不安全

有序

唯一

不为空

LinkedHashMap

线程不安全

有序

唯一

List有序可重复

Vector

和ArrayList几乎一样

Vector线程安全,效率低于ArrayList

ArrayList

优点: 底层数据结构是数组,查询快,增删慢。

因为ArrayList底层是数组实现的,根据下标查询不需要比较,查询方式为,首地址+(元素长度*下标),基于这个位置读取相应的字节数就可以了,所以非常快;增删会带来元素的移动,增加数据会向后移动,删除数据会向前移动,所以影响效率

缺点: 线程不安全,效率高

​ 线程问题:

  1. 线程安全

AA进程分为A和B, 线程C调用 A,对数据进行操作,线程D调用A对数据进行操作,这个时候线程就会出现不安全,要进行加线程锁,不让D调用A,等C调用完B(AA进程结束时),在让D调用A

  1. 线程不安全

  2. 在 Items[Size] 的位置存放此元素; 2. 增大 Size 的值。 在单线程运行的情况下,如果 Size = 0,添加一个元素后,此元素在位置 0,而且 Size=1; 而如果是在多线程情况下,比如有两个线程,线程 A 先将元素存放在位置 0。但是此时 CPU 调度线程A暂停,线程 B 得到运行的机会。线程B也向此 ArrayList 添加元素,因为此时 Size 仍然等于 0 (注意哦,我们假设的是添加一个元素是要两个步骤哦,而线程A仅仅完成了步骤1),所以线程B也将元素存放在位置0。然后线程A和线程B都继续运行,都增加 Size 的值。 那好,现在我们来看看 ArrayList 的情况,元素实际上只有一个,存放在位置 0,而 Size 却等于 2。这就是“线程不安全”了。

LinkedList

优点: 底层数据结构是双向链表,查询慢,增删快。

查询慢:根据索引查询 , 判断索引的长度 集合数据一份两, 所以查询慢

增删快:
缺点: 线程不安全,效率高

​ 和ArrayList一样

Set 无序,唯一 线程不安全

HashSet(无序)

底层数据结构是哈希表。(无序,唯一) HashSet实现Set接口,由哈希表(实际上是一个HashMap实例)支持,

底层是HasHMap

如何来保证元素唯一性?
1.依赖两个方法:hashCode()和equals()

hashCode(快,效率高,但是不安全)通过Hash表对数据进行判断是否为空

再有equals(慢 ,安全)进行判断

继承HashMap 使用HashMap的key值确保唯一

linkedHashSet(有序)

底层数据结构是双向链表和哈希表。(FIFO插入有序,唯一)

1.由链表保证元素有序(插入顺序)
2.由哈希表保证元素唯一

· 底层也是HashMap

·

TreeSet(有序)

底层数据结构是红黑树。(唯一,有序)
\1. 如何保证元素排序的呢?
自然排序
比较器排序

· TerrySet:排序

o 自然顺序:String Integer Char

o 自定义顺序:对象…

在对象类继承

public int compareTo(Student s) {
    //return -1; //-1表示放在红黑树的左边,即逆序输出
    //return 1;  //1表示放在红黑树的右边,即顺序输出
    //return o;  //表示元素相同,仅存放第一个元素
    //主要条件 姓名的长度,如果姓名长度小的就放在左子树,否则放在右子树
    int num = this.name.length() - s.name.length();
    //姓名的长度相同,不代表内容相同,如果按字典顺序此 String 对象位于参数字符串之前,则比较结果为一个负整数。
    //如果按字典顺序此 String 对象位于参数字符串之后,则比较结果为一个正整数。
    //如果这两个字符串相等,则结果为 0
    int num1 = num == 0 ? this.name.compareTo(s.name) : num;
    //姓名的长度和内容相同,不代表年龄相同,所以还要判断年龄
    int num2 = num1 == 0 ? this.age - s.age : num1;

    return num2;
}

·
2.如何保证元素唯一性的呢?

红黑树决定的
根据比较的返回值是否是0来决定

Map: HashMap、TreeMap、HashTable和LinkedHashMap

总览:

​ HashMap:数组+链表+红黑树

​ TreeMap:

​ HashTable:

LinkedHashMap:

HashMap(无序+唯一):

数组+链表+红黑树

· TreeMap是有序的,HashMap和HashTable是无序的。

  • HashMap效率较高,Hashtable效率较低。
    如果对同步性或与遗留代码的兼容性没有任何要求,建议使用HashMap。
/**
 * 程序的入口|主函数;
 * @param args
 */
public static void main(String[] args) {

    // 初始化数据对象;
    HashMap map = new HashMap();

    // 数据转载;
    map.put(null, "234");
    map.put("a", "1223");
    map.put(null, "665");

    // 获取等式键值集合;
    Set set = map.entrySet();

    /**
     * 打印数据内容;--[null=665, a=1223]
     * 根据打印结果可以看出:
     *     我们再map中存储的两个key为null的值仅仅打印了一个;
     *     并且是最后一个;
     * 也就是说:
     *     hashMap中允许存在key为null的值,只不过只能有一个;
     *     后续出现的key为null的值会覆盖前一个;
     */
    System.out.println(set);
}

TreeMap(有序+唯一):

底层是红黑树

o 自然顺序:String Integer Char

o 自定义顺序:对象…

在对象类继承

HashTable(无序):

· Hashtable的方法是同步的,HashMap的方法不是同步的。这是两者最主要的区别。

同步意味着在一个时间点只能有一个线程可以修改hash表,任何线程在执行HashTable的更新操作前都需要获取对象锁,其他线程需要等带锁的释放。

· Hashtable线程安全,HashMap 和 TreeMap 线程不安全 (Hashtable方法同步线程安全

  • Hashtable是线程安全的,HashMap是线程不安全的。

    • 原因: 都被synchronized关键字修饰这种

jdk自带的内置锁可以使得被synchronized关键字修饰的方法体和代码块一次只能被一个线程执行,也就保证了线程安全的问题。

  • 效率低:

让我们看看HashTable,HashTable本身是个容器,这也就说明了HashTable本身可以不断的放大,试想一下,HashTable如果本身如果存在1000个元素,那么在get()方法中就会将这1000个元素完全锁住,期间其他任何线程都得等待。这样就会造成容器越大,对容器数据操作的效率将越低。

  • Hashtable不允许null值,HashMap允许null值(key和value都允许,key只可以有一个,如果key有两个null值,第二个null值可以代替第一个null值)

  • 父类不同:Hashtable的父类是Dictionary,HashMap的父类是AbstractMap

LinkedHashMap(有序+唯一):

HashMap(数组+链表+红黑树)+双向链表(保证顺序)

LinkedHashMap有序,可分为插入顺序和访问顺序两种。

访问顺序:,那put和get操作已存在的Entry时,都会把Entry移动到双向链表的表尾(其实是先删除再插入)。

插入顺序: 调用get(key), 或者put(key, value)并不会对线性结构产生任何的影响。

LinkedHashMap存取数据,还是跟HashMap一样使用的Entry[]的方式,双向链表只是为了保证顺序。

LinkedHashMap是线程不安全的。

红黑树(只要用到就是唯一的)

红黑树的主要特性:  
 (1)每个节点要么是黑色,要么是红色。(节点非黑即红)  
 (2)根节点是黑色。  
 (3)每个叶子节点(NIL)是黑色。   
 (4)如果一个节点是红色的,则它的子节点必须是黑色的。(也就是说父子节点不能同时为红色)  (5)从一个节点到该节点的子孙节点的所有路径上包含相同数目的黑节点。(这一点是平衡的关键)
 说简单也简单,其实就是一颗比较平衡的又红又黑的二叉树嘛。

TreeSet红黑树:

使用二叉树存储数据

//第一次存储数据没有树根,就创建一个树根,把这个元素赋值给树根;
//第二次进行存储的时候,首先和根节点的元素进行比较,比较有三种情况:
  //第一种情况当前元素和根节点的元素相同,这是忽略该值,不存储该值;
  //第二种情况当前元素和根节点的元素相比,小于根节点元素,那么将该元素放在根节点的左边
  //第三种情况当前元素和根节点的元素相比,大于根节点元素,那么将该元素放在根节点的右边

举例:
存储下列元素: 20,18,23,22,17,24,19,18,24

               treeSet.add(20);
               treeSet.add(18);
               treeSet.add(23);
               treeSet.add(22);
               treeSet.add(17);
               treeSet.add(24);
               treeSet.add(19);
               treeSet.add(18);
               treeSet.add(24);

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rrSHbxf0-1597245100141)(file:///C:/Users/20297/AppData/Local/Temp/msohtmlclip1/01/clip_image014.png)]从上图可以看出,相同的元素18,24并没有存进集合中,并且存进去的元素 已经从小到大排好了序,所以TreeSet保证了元素的唯一以及有序。

HashMap红黑树:

​ HashMap是数组+链表+红黑树

因为红黑树需要进行左旋,右旋操作, 而单链表不需要,
如果元素小于8个,查询成本高,新增成本低(数组+链表)
如果元素大于8个,查询成本低,新增成本高(数组+链表+红黑树)

当数据大于链表的0.75(扩容因子)就会扩容2倍

7);
treeSet.add(24);
treeSet.add(19);
treeSet.add(18);
treeSet.add(24);


[外链图片转存中...(img-rrSHbxf0-1597245100141)]从上图可以看出,相同的元素18,24并没有存进集合中,并且存进去的元素 已经从小到大排好了序,所以TreeSet保证了元素的唯一以及有序。

 

## HashMap红黑树:

​    HashMap是数组+链表+红黑树

因为红黑树需要进行左旋,右旋操作, 而单链表不需要,
    如果元素小于8个,查询成本高,新增成本低(数组+链表)
    如果元素大于8个,查询成本低,新增成本高(数组+链表+红黑树)

当数据大于链表的0.75(扩容因子)就会扩容2倍

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Java 2集合框架图  集合接口:6个接口(短虚线表示),表示不同集合类型,是集合框架的基础。  抽象类:5个抽象类(长虚线表示),对集合接口的部分实现。可扩展为自定义集合类。  实现类:8个实现类(实线表示),对接口的具体实现。  在很大程度上,一旦您理解了接口,您就理解了框架。虽然您总要创建接口特定的实现,但访问实际集合的方法应该限制在接口方法的使用上;因此,允许您更改基本的数据结构而不必改变其它代码。  · Collection 接口是一组允许重复的对象。  · Set 接口继承 Collection,但不允许重复,使用自己内部的一个排列机制。  · List 接口继承 Collection,允许重复,以元素安插的次序来放置元素,不会重新排列。  · Map接口是一组成对的键-值对象,即所持有的是key-value pairs。Map不能有重复的key。拥有自己的内部排列机制。  · 容器的元素类型都为Object。从容器取得元素时,必须把它转换成原来的类型。  Java 2简化集合框架图  集合接口  1.Collection 接口  用于表示任何对象或元素组。想要尽可能以常规方式处理一组元素时,就使用这一接口。  (1) 单元素添加、删除操作:   boolean add(Object o):将对象添加给集合   boolean remove(Object o): 如果集合有与o相匹配的对象,则删除对象o  (2) 查询操作:   int size() :返回当前集合元素的数量   boolean isEmpty() :判断集合是否有任何元素   boolean contains(Object o) :查找集合是否含有对象o

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值