集合总结

集合

Collection接口是集合类的根接口, java中没有提供这个接口的直接的实现类. 有两个接口继承了它, Set和List. 其中Set为无需的集合,元素不可重复, List为有序集合,元素可重复.
Map是java.util包中的另一个接口, 和Collection接口没有关系, 相互独立, 但都是结合类的一部分. Map的存储形式为key-value, 元素的key不可重复,value可重复
说道集合不得不说Iterator, 所有的集合类都实现了Iterator接口, 这个接口用于遍历集合中元素的接口: 主要应用其中的三个方法:
hasNext(): 判断是否存在下一个元素, next()返回下一个元素, remove()删除当前元素
List接口的实现类主要有ArrayList和LinkedList
ArrayList集合底层实现是数组,因为数组有索引, 所以查询速度较高, 不过由于元素的有序性和数组长度的固定, 索引在插入和删除元素时, 都要移动数组中所有元素,而且还要扩容, 所以添加和删除元素的效率不高.
LinkedList集合底层是链表结构, 数据添加删除效率高, 只需要改变指针即可, 但是查询访问效率低, 需要遍历链表,直到找到目标元素.
Collections是java.util下的类,是一个包装类它包含各种关于集合操作的静态方法, 此类不可以实例化, 像一个工具类, 服务于java的Collection框架
ArrayList的安全性
ArrayList添加元素分为两个步骤: 第一步现在索引为size的位置上存放元素, 第二步: size的值加一. 所谓线程不安全, 就是如果有一个线程A添加元素1在当前索引出, 但还没有完成第二步, CPU调度线程A暂停, 此时的当前索引没有改变, 接着线程B添加元素2, 在当前索引处, 因为上次添加元素时索引未变, 所以此时的2覆盖之前1, 此时集合中只添加了一个元素, 之后线程A,B都会去将size加一, 结果就是: 添加一个元素, 而索引却增加2,故线程不安全.

ArrayList数据结构分析

未完–

迭代器

迭代器是对象, 他的工作遍历是遍历并获取存储对象, 通过迭代器, 开发人员可以不了解容器底层的数据结构, 就可以实现容器的遍历.
使用迭代器时需要注意:
常常会遇到: ConcurrentModificationException异常, 原因通常为: 使用iterator遍历容器的同时又对容器做增加或删除操作或多线程导致.
具体原因:
当调用容器的iterator()方法返回iterator对象时, 把容器中包含的对象数量赋值给变量expectedModCount, 在调用next()方法时会比较变量expectedModCount与实际对象的个数modCount的值是否相等, 若二者不相等, 会抛出ConcurrrentModificationException异常, 一次使用Ierator遍历容器过程中, 如果对容器进行增删操作, 就会改变容器中对象的数量, 此时expctedModCount和modCount的值不相等,导致抛出异常.
解决方法:
单线程中: 在遍历的过程中把需要删除的对象报错到一个集合中,等遍历结束后再调用removeAll()方法来删除
多线程中:
1)jdk1.5版本中引入了线程安全的方案, 提供了线程安全的容器, 例如: ConcurrentHashMap和CopyOnWriteArrayList等
2)使用迭代器遍历容器时对容器的操作放到synchronized代码块中, 但是当并发量比较高的时候, 会严重影响程序性能, 不建议使用.

Map

map是java.util包下的接口, 包含三个实现类: HashMap, HashTable, TreeMap, Map类型的集合是存储键值对的数据结构, 通过key对象进行索引, 对应的对象为value,其中key对象不可以重复, value可以重复.
HashMap和HashTable的区别:
HashMap是jdk1.2引进的Map interface的实现类, 而HashTable是继承自Dictionary类,
HashMap支持key-value为null(允许一个),HashTable不允许有null
HashMap是线程不安全的, HashTable是线程安全的, 所以HashMap效率较高

Key唯一性原理:
在向map集合中put元素时, 先根据key的hash值得到这个元素在数组中的位置,就是所谓的下标, 在存放前先判断该位置是否已经存放了其他元素, 如果有就通过equal方法对比该位置存放的元素是否存在相同元素, 如果有覆盖,没有就存放, 在同一位置存放的元素将以链表的形式存放, 新加入的元素放在链头, 首次存放的在链尾.
当hashmap中get元素时,与put过程大致相同, 首先计算key的hashcode, 找到数组中的对应位置, 然后通过key的equals方法在对应位置的链表中找到需要的元素.
综上所述: 如果数组中每个位置只有一个元素, 无疑查询速度是最快的, 我们需要做的就是将需要存放的元素, 在链表位置上尽量分散开来, 以此来提高Hashmap的查询效率, 其关键就在于获取数组位置的算法-hash算法

Hash算法
首先计算key的hashcode值, 然后跟数组的长度-1做一次”与”运算(&), 此处hashmap很巧妙的利用2的n次幂作为hashmap的预设值, 使得不同的index相同的几率较小, 那么数据在数组上分布就比较均匀, 也就是说碰撞的几率变小, 查询效率变高.
所以虽好预设hashmap的size为2的整数次幂方

HashMap的resize
当hashmap中存储的元素越来越多时, 碰撞的几率就越来越高,所以为了提高查询效率, hashmap数组的扩容是必然的, 在hashmap数组扩容之后,原来数组中的数据必须重新计算在新数组上的位置, 此时很消耗性能.
综上所述: 频繁的扩容操作会很消耗性能, 所以在创建hashmap集合时, 应该设置合适的size, 扩容时机: 当hashmap中的元素个数超过size*loadFactor时. loadFactor默认值为0.75,
所以, 如果你需要存储1000个元素, 将size设置为1000/0.75=1333, 但并不符合2的整次幂方原则, 应设置为1256

Java与运算:
int a=129;
int b=128;
a 和b 与的结果是:128
下面分析这个程序:
“a”的值是129,转换成二进制就是10000001,而“b”的值是128,转换成二进制就是10000000。根据与运算符的运算规律,只有两个位都是1,结果才是1,可以知道结果就是10000000,即128。
所以注意: 在Map中存储的类对象, 必须重写equals方法和hashCode方法

java中有三种移位运算符
<< : 左移运算符,num << 1,相当于num乘以2

 :     右移运算符,num >> 1,相当于num除以2

: 无符号右移,忽略符号位,空位都以0补齐

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值