java集合详解

java集合详解

1. java集合概述

​ 集合类是Java数据结构的实现。Java的集合类是java.util包中的重要内容,它允许以各种方式将元素分组,并定义了各种使这些元素更容易操作的方法。Java集合类是Java将一些基本的和使用频率极高的基础类进行封装和增强后再以一个类的形式提供。集合类是可以往里面保存多个对象的类,存放的是对象,不同的集合类有不同的功能和特点,适合不同的场合,用以解决一些实际问题。

2. java集合与数组的区别

数组的长度是在创建的时候是固定的,集合的长度是可以动态变化的。
数组中存放基本数据类型和引用类型,集合存放的是引用类型不能存放基本数据类型(若是简单的int,它会自动装箱成Integer)

3. java集合的特点

集合用于存储对象的容器,对象是用来封装数据,对象多了也需要存储集中式管理。
对象的个数确定可以使用数组,对象的个数不确定的可以用集合。因为集合是可变长度的。

4. java集合框架图

java 集合:

集合

Collection集合:

collection

Map集合:

map

5. java集合体系

Collection 和 Map 是 Java 集合框架的根接口,这两个接口又包含了一些子接口或实现类

Collection接口:单列数据,定义了存取一组允许重复对象的方法的集合

  • List:集合中的元素是有序集合,集合中的元素可以重复(动态数组),访问集合中的元素可以根据元素的索引来访问
  • Set:集合是无序集合,集合中的元素不可以重复,访问集合中的元素只能根据元素本身来访问(也是集合里元素不允许重复的原因)

Map接口:双列数据,集合中保存具有映射关系“key-value对”的元素,访问时只能根据每项元素的 key 来访问其 value

5.1 迭代器 Iterator

​ 它是Java集合的顶层接口,Iterator 接口提供遍历任何 Collection 的接口。我们可以从一个 Collection 中使用迭代器方法来获取迭代器实例。迭代器取代了 Java 集合框架中的 Enumeration,迭代器允许调用者在迭代过程中移除元素。

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

public class test {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("q");
        Iterator<String> it = list. iterator();
        while(it. hasNext()){
            String obj = it. next();
            System. out. println(obj);
        }
    }
}

//结果
q

边遍历边修改 Collection 的唯一正确方式是使用 Iterator.remove() 方法

Iterator<Integer> it = list.iterator();
while(it.hasNext()){
   it.remove();
}
5.2 Collection接口
5.2.1 List子接口

允许存储有序的、可重复的数据

ArrayList(常用子类)
  • 有序,非线程安全,可为null,可重复 ,查询快,插入、删除慢、效率高。
  • 底层实现Object数组,它实现了Serializable接口,因此它支持序列化。

  • 默认容量为10,当数据超过当前容量会进行自动扩容,每次扩容原数组的1/2 。

使用:随机访问比较多就使用ArrayList

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

public class TestArrayList {
    public static void main(String[] args) {
        // 在创建一个ArrayList对象时一般将其向上转型为List,
        List<Integer> list = new ArrayList<>();
        // 在定义时,建议加上泛型
        list.add(1);
        list.add(3);
        list.add(5);
        // List 独有方法 ,将下标为2的元素修改为9
        Integer set = list.set(2, 9);
        System.out.println(list.get(2));
    }

}

//结果
9
LinkedList(常用子类)
  • 有序、非线程安全,插入、删除快、查询效率不高

  • 底层为双向链表

使用:插入删除比较多的时候就选用LinkedList

import java.util.LinkedList;
import java.util.List;

public class TestLinkedList {

    public static void main(String[] args) {
        // 在创建一个LinkedList对象时一般将其向上转型为List
        List<Integer> list = new LinkedList<>();
        // 在定义时,建议加上泛型
        list.add(1);
        list.add(3);
        list.add(5);
        // List 独有方法 ,将下标为2的元素修改为9
        Integer set = list.set(2, 9);
        System.out.println(list.get(2));
    }
}

//结果
9
Vector(不常用)
  • 有序,可重复,查询快,插入、删除慢

  • 底层实现Object数组,跟ArrayList结构相似,线程安全的,加了synchronized,

  • 效率低,一般不常用,在考虑到线程并发访问的情况下才会去使用Vector子类

**Stack栈:**后进先出(LIFO),继承自Vector,也是数组,线程安全的栈。

但作为栈数据类型,不建议使用Vector中与栈无关的方法,尽量只用Stack中的定义的栈相关方法,这样不会破坏栈数据类型。

使用:要求线程安全就选用Vector

import java.util.List;
import java.util.Vector;

public class TestVector {
    public static void main(String[] args) {
        // 在创建一个Vector对象时一般将其向上转型为List,
        List<Integer> list = new Vector<>();
        // 在定义时,建议加上泛型
        list.add(1);
        list.add(3);
        list.add(5);
        // List 独有方法 ,将下标为2的元素修改为9
        Integer set = list.set(2, 9);
        System.out.println(list.get(2));
    }
}

//结果
9
5.2.2 Set子接口

单列无序集合(唯一)

HashSet(常用子类)
  • 无序,唯一,允许为null,不是线程安全的,存取速度比较快,不允许保存重复元素(可以实现去重操作)。

  • 底层是HashMap,放到HashSet集合中的元素等同于放到HashMap集合key部分了

  • HashSet 按 Hash 算法来存储集合中的元素,因此具有很好的存取、查找、删除性能

  • 向HashSet中添加元素的过程:

    • 当向 HashSet 集合中存入一个元素时,HashSet 会调用该对象的 hashCode() 方法来得到该对象的 hashCode 值,然后根据 hashCode 值,通过某种散列函数决定该对象在 HashSet 底层数组中的存储位置。(这个散列函数会与底层数组的长度相计算得到在数组中的下标,并且这种散列函数计算还尽可能保证能均匀存储元素,越是散列分布,该散列函数设计的越好)
    • 如果两个元素的hashCode()值相等,会再继续调用equals方法,如果equals方法结果为true,添加失败;如果为false,那么会保存该元素,但是该数组的位置已经有元素了,那么会通过链表的方式继续链接。
    • 如果两个元素的 equals() 方法返回 true,但它们的 hashCode() 返回值不相等,hashSet 将会把它们存储在不同的位置,但依然可以添加成功。

简化:

首先判断hashCode()值是否相同
	->继续执行equals(),看其返回值
	->true:说明元素重复,不添加
	  是false:就直接添加到集合
	->否:就直接添加到集合
最终自动生成hashCode()equals()

LinkedHashSet: LinkedHashSet 继承与 HashSet,并且其内部是通过 LinkedHashMap 来实现的。有点类似于我们之前说的

public int hashCode();   // 对象编码
public boolean equals(Object obj); // 对象比较
TreeSet(常用子类)
  • 有序,唯一,不重复 ,不允许为null主要用作排序,自然排序和定制排序,默认情况下,TreeSet 采用自然排序。

  • 底层是TreeMap,放到TreeSet集合中的元素等同于放到TreeMap集合key部分了,红黑树(自平衡的排序二叉树)

  • TreeSet的有序存储,存储元素时会判断他是否重复,并且自动排序,判断重复元素由compareTo()方法来实现。因此自定义类要使用TreeSet必须覆写Comparable接口。具体的排序规则可以由我们自己来定

package com.java8;

import java.util.Set;
import java.util.TreeSet;

public class TestTreeSet {
    public static void main(String[] args) {
        Set<String> all = new TreeSet<>();
        all.add("hello");
        all.add("123");
        all.add("123");
        all.add("Hello jake");
        System.out.println(all);
    }
}

//结果
[123, Hello jake, hello]
5.2.3 Queue队列
  • ArrayDeque数组实现的双端队列,可以在队列两端插入和删除元素,数组队列,先进先出(FIFO)
  • 和LinkedList一样也是双向链表

PriorityQueue:

  • 优先队列,保存队列元素的顺序并不是按照加入的顺序,而是按照队列元素的大小进行排序的,数组实现的二叉树,完全二叉树实现的小顶堆(任意一个非叶子节点的权值,都不大于其左右子节点的权值)。
  • 不允许插入null元素。

Deque:

接口是Queue接口的子接口,它代表一个双端队列,当程序中需要使用“栈”这种数据结构时,推荐使用ArrayDeque。

5.3 Map接口

是存放一对值的最大接口,即接口中的每个元素都是一对,以 key➡value 的形式保存。

实现类数据结构是否线程安全key能否为null是否有序
HashMap数组+链表+红黑树
LinkedHashMap数组+链表+红黑树+双重链接列表
HashTable数组+链表
Treemap红黑树
5.3.1 HashMap

HashMap是 Map 接口使用频率最高的实现类。

  • 允许使用null键和null值,与HashSet一样,不保证映射的顺序。
  • 所有的key构成的集合是Set:无序的、不可重复的。所以,key所在的类要重写:equals()和hashCode()
  • 所有的value构成的集合是Collection:无序的、可以重复的。所以,value所在的类要重写:equals()
    一个key-value构成一个entry
  • 所有的entry构成的集合是Set:无序的、不可重复的
    HashMap 判断两个 key 相等的标准是:两个 key 通过 equals() 方法返回 true,hashCode 值也相等。
    HashMap 判断两个 value相等的标准是:两个 value 通过 equals() 方法返回 true。

注:

JDK 7及以前版本:HashMap是数组+链表结构(即为链地址法)
JDK 8版本发布以后:HashMap是数组+链表+红黑树实现。

import java.util.HashMap;
import java.util.Map;

public class TestHashMap {
    public static void main(String[] args) {
        Map<String, Integer> map = new HashMap<String, Integer>();
        map.put("one", 1);
        map.put("two", 2);
        //key重复会发生覆盖
        map.put("one", 12);
        //允许key值和value值为null
        map.put("zero", null);
        map.put(null, 1);
        System.out.println(map.get("one"));
        System.out.println(map.get(null));
        //指定的key不存在的时候返回null
        System.out.println(map.get("ten"));
    }
}

//结果
12
1
null

**LinkedHashMap:**LinkedHashMap继承了HashMap,是Map接口的哈希表和链接列表实现,它维护着一个双重链接列表,此链接列表定义了迭代顺序,该迭代顺序可以是插入顺序或者是访问顺序。

5.3.2 HashTable
  • Hashtable是早期的字典实现类,可以方便的实现数据的查询
  • Hashtable和HashMap从存储结构和实现来讲有很多相似之处,不同的是它承自Dictionary类,而且是线程安全的,另外Hashtable不允许key和value为null,并发性不如ConcurrentHashMap。
  • Hashtable不建议在新代码中使用,不需要线程安全的场合可以用HashMap替换,需要线程安全的场合可以用ConcurrentHashMap替换。
import java.util.Hashtable;
import java.util.Map;

public class TestHashtable {
    public static void main(String[] args) {
        Map<Integer, String> map = new Hashtable<Integer, String>();
        map.put(1, "1");
        map.put(2, "2");
        System.out.println(map);
    }
}

//结果
{2=2, 1=1}
Properties
  • Properties 类是 Hashtable 的子类,该对象用于处理属性文件
  • 由于属性文件里的 key、value 都是字符串类型,所以 Properties 里的 key 和 value 都是字符串类型
  • 存取数据时,建议使用setProperty(String key,String value)方法和getProperty(String key)方法
5.3.3 Treemap

​ Map集合的主要功能是依据key实现数据的查询需求,为了方便进行key排序操作提供了TreeMap集合,
TreeMap实现SortMap接口,能够把它保存的记录根据键排序,默认是按键值的升序排序(自然顺序),也可以指定排序的比较器,当用Iterator遍历TreeMap时,得到的记录是排过序的。

import java.util.Map;
import java.util.TreeMap;

public class TestTreeMap {
    public static void main(String[] args) {
        Map<Integer, String> map = new TreeMap<Integer, String>();
        map.put(1, "1");
        map.put(2, "2");
        System.out.println(map);
    }
}

//结果
{1=1, 2=2}

6.总结

​ java集合知识总结的文章就介绍到这了,这边列举了部分例子供参考,仅作为学习笔记使用,欢迎批评指正,要是感兴趣可以关注微信订阅号 程序own

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值