Java-集合

集合

image-20210924222216778

存储结构

存储结构:顺序存储(数组)、链式存储(链表)
逻辑结构:栈、队列、线性表、树、图
线性表有两种存储方式,顺序表和链表
栈有顺序栈和链栈

分类

集合分为两大类
单列集合、双列集合

单列集合(Collection)又分为List(ArrayList、LinkedList、Vector)和Set(HashSet、LinkedHashSet、TreeSet)
双列集合(Map)又分为HashMap、TreeMap、Hashtable、Properties

ArrayList线程是不安全的、Vector线程是安全的、LinkedList线程是不安全的、Map里面的Hashtable、Properties线程是安全的

抑制警告错误

@SuppressWarnings("{all}");

线程安全

Vector、Hashtable、Properties

List接口

方法作用
add添加一个元素
remove删除指定元素(可以是下标也可以是数据,如果是int类型就需要转化为包装类Integer)
size获取元素个数(集合长度)
isEmpty判断是否为空
clear清空
addAll添加多个元素(添加另一个集合中的所有元素)
containsAll查找多个元素是否都存在
removeAll删除多个元素

注意:所有带All的方法里面传的都是集合

List list = new ArrayList<>();
list.add(12);
list.add(13);
list.add(14);
System.out.println(list);
System.out.println("=========");
//如果需要删除整数,则要将其换为包装类Integer
list.remove((Integer)13);
System.out.println(list);
System.out.println("=========");
System.out.println(list.size());
System.out.println("=========");
list.clear();
System.out.println(list);
List list1 = new ArrayList();
list1.add("红楼梦");
list1.add("三国演义");
list.addAll(list1);
System.out.println(list);
System.out.println(list.containsAll(list1));
list.add(4);
list.removeAll(list1);
System.out.println(list);

迭代器的执行原理

//获取Set集合的迭代器
Iterator it = set.iterator();
//通过hasNext方法判断是否还有下一个元素
while (it.hasNext()){
    //指针下移,将下移后的位置的元素输出
    System.out.println(it.next());
}
//当while循环结束后,这时迭代器指向最后的元素,如果这时再使用it.next()就会出现异常
//如果需要再次遍历集合,就需要重置迭代器it = set.iterator();重新获取一下迭代器就可以完成重置

扩展:当创建迭代器对象后(Iterator it = set.iterator()),可以使用itit快捷键快速生成迭代器的while循环

//增强for循环就是迭代器的简化版,可以代替迭代器遍历集合或数组
//增强for循环的底层也是迭代器
//只能使用在数组和实现了Iterable接口的集合中,如果一个类中的集合没有实现Iterable,可以在类声明处实现Iterable接口,就可以使用增强for
for (Object s:list
             ) {
            System.out.println(s);
        }

Vector

  • Vector与ArrayList的比较
底层结构线程安全效率扩容机制
ArrayList可变数组不安全,效率高,查询快如果有参构造1.5倍。无参第一次是10,第二次扩容1.5倍
Vector可变数组安全,效率不高,查询快如果无参,默认是10,满后,2倍扩容。如果指定大小,则每次直接按2倍扩容
LinkedList双向链表不安全,增删快,查询慢

LinkedList

LinkedList实现了双向链表和双端队列的特点
可以添加任意元素,包括null
线程是不安全的,没有实现同步

Set接口

(1)无序(添加和取出的顺序不一致,没有索引)
(2)不允许重复元素,所以最多包含一个null
(3)JDK中Set实现的子类有HashSet、TreeSet、LinkedHashSet等等
遍历方式
	(1)迭代器
	(2)增强for
	(3)不能使用索引的方式来获取

HashSet

集合中的元素是无序排列的
HashSet类是非线程安全的允许集合元素为null(只能有一个)
只能使用增强for循环或迭代器遍历

哈希表是以数组加链表加红黑树来存储数据的。
当相同哈希值的元素大于等于8个时(即哈希冲突的元素超过8个),就会使用红黑树来储存,因为红黑树查询效率很高。
哈希表的存储是首先通过哈希函数来计算哈希值(hashcode())来确定你要放到哈希表里面的哪一个位置。

当往里面存储元素时,首先会调用hashcode()方法,计算哈希值,然后判断哈希表中有没有这个值,如果没有那么直接储存,如果有,即发生了哈希冲突,然后再调用equals方法判断所存储的元素和相同哈希值的元素是否一样,如果不同,则将新的也进行存储,如果相同,则不存储。
如果新添加的元素与集合中已有的某个元素哈希值相同,此时还需要调用equals(Object obj)比较
如果equals(Object obj)方法返回true,说明新添加的元素与集合中已有的某个元素的属性值相同,那么新添加的元素不存入集合
如果equals(Object obj)方法返回false, 说明新添加的元素与集合中已有的元素的属性值都不同, 那么新添加的元素存入集合

hashCode是对象的一个int类型的哈希值,散列值,是由对象的还是从的()方法提供的,通过哈希值来确定存储的位置

LinkedHashSet

LinkedHashSet继承自HashSet,它的添加、删除、查询等方法都是直接用的HashSet的,唯一的不同就是它使用LinkedHashMap存储元素
(1LinkedHashSet的底层使用LinkedHashMap存储元素。
(2LinkedHashSet是有序的,它是按照插入的顺序排序的。
(3LinkedHashSet是不支持按访问顺序对元素排序的,只能按插入顺序排序

TreeSet

TreeSet 是一个有序的集合,它的作用是提供有序的Set集合。它继承于AbstractSet抽象类,实现了NavigableSet<E>, Cloneable, java.io.Serializable接口。
TreeSet 继承于AbstractSet,所以它是一个Set集合,具有Set的属性和方法。
TreeSet 实现了NavigableSet接口,意味着它支持一系列的导航方法。比如查找与指定目标最匹配项。
TreeSet 实现了Cloneable接口,意味着它能被克隆。
TreeSet 实现了java.io.Serializable接口,意味着它支持序列化。
TreeSet是有序的Set集合,因此支持add、remove、get等方法。
NavigableSet一样,TreeSet的导航方法大致可以区分为两类,一类时提供元素项的导航方法,返回某个元素;另一类时提供集合的导航方法,返回某个集合。
lower、floor、ceiling 和 higher 分别返回小于、小于等于、大于等于、大于给定元素的元素,如果不存在这样的元素,则返回 null

Map接口

HashMap

Properties继承自HashtableLinkedHashMap继承自HashMap、实现了Map接口
MapCollection并列从在,用于保存具有映射关系的数据:Key-Value
Map中的KeyValue可以是任何引用类型的数据,会封装到HashMap对象中
Map中的key不允许重复,原因和HashSet一样
Map中的value可以重复
Map中的key可以为null,value也可以为null,注意可以null只有一个,value为null可以有多个
常用String类作为Map的key
key和value之间存在单向一对一的关系,即通过指定的key可以找到对应的value
**注意**:当key相同时,会将value的值进行替换

//遍历TreeMap的键
// 假设map是TreeMap对象
// map中的key是String类型,value是Integer类型
String key = null;
Integer integ = null;
Iterator iter = map.keySet().iterator();
while (iter.hasNext()) {
        // 获取key
    key = (String)iter.next();
        // 根据key,获取value
    integ = (Integer)map.get(key);
}
//遍历值
// 假设map是TreeMap对象
// map中的key是String类型,value是Integer类型
Integer value = null;
Collection c = map.values();
Iterator iter= c.iterator();
while (iter.hasNext()) {
    value = (Integer)iter.next();
}
JDK1.7与1.8区别
不同JDK 1.7JDK 1.8
存储结构数组 + 链表数组 + 链表 + 红黑树
初始化方式单独函数:inflateTable()直接集成到了扩容函数resize()
hash值计算方式扰动处理 = 9次扰动 = 4次位运算 + 5次异或运算扰动处理 = 2次扰动 = 1次位运算 + 1次异或运算
存放数据的规则无冲突时,存放数组;冲突时,存放链表无冲突时,存放数组;冲突 & 链表长度 < 8:存放单链表;冲突 & 链表长度 > 8:树化并存放红黑树
插入数据方式头插法(先讲原位置的数据移到后1位,再插入数据到该位置)尾插法(直接插入到链表尾部/红黑树)
扩容后存储位置的计算方式全部按照原来方法进行计算(即hashCode ->> 扰动函数 ->> (h&length-1))按照扩容后的规律计算(即扩容后的位置=原位置 or 原位置 + 旧容量)

Hashtable

和HashMap一样,Hashtable 也是一个散列表,它存储的内容是键值对(key-value)映射。
Hashtable 继承于Dictionary,实现了Map、Cloneable、java.io.Serializable接口。
Hashtable 的函数都是同步的,这意味着它是线程安全的。它的key、value都不可以为null。此外,Hashtable中的映射不是有序的。
Hashtable 的实例有两个参数影响其性能:初始容量 和 加载因子。容量 是哈希表中桶 的数量,初始容量 就是哈希表创建时的容量。注意,哈希表的状态为 open:在发生“哈希冲突”的情况下,单个桶会存储多个条目,这些条目必须按顺序搜索。加载因子 是对哈希表在其容量自动增加之前可以达到多满的一个尺度。初始容量和加载因子这两个参数只是对该实现的提示。关于何时以及是否调用 rehash 方法的具体细节则依赖于该实现。
通常,默认加载因子是 0.75, 这是在时间和空间成本上寻求一种折衷。加载因子过高虽然减少了空间开销,但同时也增加了查找某个条目的时间(在大多数 Hashtable 操作中,包括 get 和 put 操作,都反映了这一点)。
HashMap与Hashtable区别
HashMap和Hashtable都实现了Map接口
HashMap是非synchronized,而Hashtable是synchronized
HashTable使用Enumeration,HashMap使用Iterator
HashMap允许将 null 作为一个 entry 的 key 或者 value,而 Hashtable 不允许。

LinkedHashMap

LinkedHashMap是HashMap的子类,与HashMap有着同样的存储结构,但它加入了一个双向链表的头结点,将所有put到LinkedHashmap的节点一一串成了一个双向循环链表,因此它保留了节点插入的顺序,可以使节点的输出顺序与输入顺序相同。
LinkedHashMap可以用来实现LRU算法
LinkedHashMap同样是非线程安全的,只在单线程环境下使用。
LinkedHashMap是否允许空Key和Value都允许空
LinkedHashMap是否允许重复数据Key重复会覆盖、Value允许重复
LinkedHashMap是否有序有序
LinkedHashMap是否线程安全非线程安全

TreeMap

TreeMap是一个有序的key-value集合,它是通过红黑树实现的。
TreeMap继承于AbstractMap,所以它是一个Map,即key-value集合。
TreeMap实现了NavigableMap接口,意味着它支持一系列的导航方法。比如返回有序的key集合。
TreeMap实现了Clonable接口,意味着它能被克隆。
TreeMap实现了java.io.Serializable接口,意味着它支持序列化。
TreeMap基于红黑树实现,该映射根据其键的自然顺序进行排序,或者根据创建映射时提供的Comparator进行排序,具体取决于使用的构造方法
TreeMap是非同步的,它的iterator方法返回的迭代器是fail-fastl的

Properties

表示一个持久的集,可以存在流中或者从流中加载。用来读取Java的配置文件,在Java中为.properties为后缀名的文本文件。
是 Hashtable子类,map集合方法都可以用。
常用的方法
  getProperties(String key):通过指定的键搜索属性。
  setProperties(String key,String value):相当于Hashtable中的put方法
  load(InputStream inStream):方法读取属性列表(键和元素对)从输入字节流。输入流是一个简单的面向行的格式为负载器(Reader)指定的。
  store(OutputStream outStream):将此属性列表(键和元素对)写入此Properties表中,以适合使用load(InputStream)方法加载到Properties表中的格式输出流。
  clear() 清除所有加载。
方法
containsKey:查找键是否存在
keySet:获取所有的键
entrySet:获取所有关系
values:获取所有的值
六大遍历
//获取所有的key,通过key找到value
Set keyset = map.keySet();
//(1)增强for
for (Object key:keyset
) {
System.out.println(key+"-"+map.get(key));
}
//(2)迭代器
Iterator iterator = keyset.iterator();
while (iterator.hasNext()) {
Object next =  iterator.next();
System.out.println(next);
}

/取出所有的value,只能显示value
Collection values = map.values();
//增强for
for (Object obj:values
) {
System.out.println(obj);
}
//迭代器
Iterator iterator = values.iterator();
while (iterator.hasNext()) {
Object next =  iterator.next();
System.out.println(next);
}

//通过entrySet获取K-y
Set entrySet = map.entrySet();
for (Object obj:entrySet
    ) {
    System.out.println(obj);
}
Iterator iterator = entrySet.iterator();
while (iterator.hasNext()) {
    Object next =  iterator.next();
    System.out.println(next);
}
扩容
HashMap当链表的数超过8,并且数组的长度超过64,就会进行树化,而不是进行扩容

集合和数组的区别

(1)数组是固定长度的,集合可变长度的
(2)数组可以存储基本数据类型,也可以存储引用数据类型
(3)数组存储的元素必须是同一个数据类型,集合存储的对象可以是不同数据类型

使用集合框架的好处

(1)容量自增长
(2)提供了高性能的数据结构和算法,使编码更轻松,提高了程序速度和质量
(3)允许不同API之间的互操作,API之间可以来回传递集合
(4)可以方便地扩展或改写集合,提高代码复用性和操作性
(5)通过使用JDK自带的集合类,可以降低代码维护和学习新API成本

List、Set、Map三者的区别

List:一个有序(元素存入集合的顺序和取出的顺序一致)容器,元素可以重复,可以插入多个null元素,元素都有索引。常用的实现类有ArrayList、LinkedList和Vector
Set:一个无序(存入和取出顺序有可能不一致)容器,不可以存储重复元素,只允许存入一个null元素,必须保证元素唯一性。Set接口常用实现类是HashSet、LinkedHashSet和TreeSet
Map:是一个键值对集合,存储键、值和之间的映射,Key无序、唯一,value不要求有序,允许重复。Map没有继承于Collection接口,从Map集合中检索元素时,只要给出键对象,就会返回对饮的值对象

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值