数组
一、数组声明了它容纳的元素的类型,而集合不声明。 二、数组是静态的,一个数组实例具有固定的大小,一旦创建了就无法改变容量了。而集合是可以动态扩展容量, 可以根据需要动态改变大小,集合提供更多的成员方法,能满足更多的需求。 数组会做边界检查(检查边界会以效率为代价) 三、数组的存放的类型只能是一种(基本类型/引用类型),集合存放的类型可以不是一种(不加泛型时添加的类型是Object)。 四、数组是java语言中内置的数据类型,是线性排列的,执行效率或者类型检查都是最快的
集合
Collection Map ------->都是接口 / / | / / | (List Set) (HashMap TreeMap HashTable) 类 Collections中 public staticvoid sort(List list, Comparator super T> c)根据指定比较器产生的顺序对指定列表进行排序 长度可以动态改变 存储不同类型的对象和数据 boolean retainAll(Collection> c) 如果此 collection 由于调用而发生更改,则返回 true 数据结构 ├栈:先进后出 子弹夹 ├队列:先进先出 排队买票 ├数组:查询快,添加删除慢 ├树: └链表:添加删除快,查询慢 ├单向链表 ├双向链表 └循环链表 (加载因子:当元素个数达到集合长度*加载因子的长度后,会触发扩容) List(有序集合(存和取顺序一致),允许相同元素和null) ├ArrayList 初始容量10,加载因子为0.5,扩容增量:0.5倍+1,即第一次扩容:10*1.5+1=16 │ ├底层是数组 │ ├线程不安全,不同步 │ ├查询修改快,插入删除慢 │ └ListIterator(主要用于List迭代) │ ├可以逆向输出,是Iterator的子接口 │ └ListIterator在遍历时,使用ListIterator类中的add()和remove()方法对List数据进行操作是不会有并发异常; │ Iterator在遍历时,对list的进行数据操作会抛出并发异常 ConcurrentModificationException ├Vector(基本不使用) 初始容量10,加载因子1,扩容增量为1倍 │ ├底层是数组,查询修改快,删除增加慢 │ ├线程安全,同步 │ ├firstElement() 返回此向量(位于索引0)一个组件 │ └lastElement() 返回此向量的最后一个组件 └linkeList ├底层是链表,查询修改速度慢,删除增加快 ├线程不安全,不同步 ├addFirst() addLast() 将指定元素插入此列表的开头或结尾 └gteFirst() getLast() 获取此列表的开头或结尾元素 Set (无序集合,不允许相同元素,最多有一个null元素) ├HashSet 最多有一个null元素;初始容量16,加载因子为0.75,扩容增量为一倍(与HashMap等同) │ ├hashCode()和equals() │ │ └HashSet底层是hashCode()和equals()进行去重,先比较hashCode()是否相等,如果不相等,返回false(即不重复); │ │ 如果相等,会在进行equsals()方法比较,如果equals()返回true,则去重,否则不去重。 │ └遍历 │ ├foreach │ └Iterator └TreeSet ├不能存null ├存入的对象的类必须使用比较器,否则会抛出类转换异常 └比较器 ├实现 comparable 重写compareTo方法 └TreeSet(Comparator super E> comparator) 自定义裁判类实现Comparator接口,重写compare(),并将此类对象作为参数传入TreeSet() Map (没有实现collection接口,key不能重复,value可以重复,一个key映射一个value,允许null为key和value) ├Hashtable (实现Map接口,同步,不允许null作为key和value,用自定义的类当作key的话要复写hashCode和eques方法,) ├HashMap (实现Map接口,非同步,允许null作为key和value,用的多) 初始容量16 └TreeMap (实现Map接口,根据自然顺序(或指定规则)顺序对key进行排序,非同步,不允许null为key)
哈希算法相关知识点
a. java中的每个对象都有一个“哈希码”, “哈希码”其实就是一个整数(包括正数和负数)
b. jdk内置的类的对象,哈希码都是根据内容计算出来的,也就说,内容相同的两个对象,哈希码一定相同。
c. 那么我们自定义的类,哈希码是否与内容有关: 无关!! why??
因为,我们自定义的类,并没有重写Object的hashcode方法,所以调用自定义的类的hashcode方法时,
会直接调用父类Object的hashcode方法,而父类Object的hashcode方法恰恰返回的是对象在堆内存中的地址!
d. 我们也想让自定义的类的hashcode也是根据内容就算出来的,就需要重写Object的hashcode方法。
保证自定义的类的hashCode是根据内容计算出来的!
e. 当我们把一个对象加入HashSet的时候,HashSet(内部是HashMap)会根据对象的hashCode来分配对象进入的区域,也就说,
哈希码相同的2个对象会进入同一片区域,进入同一片区域的对象就会引起比较,而比较的时候,又会回调对象的
equals. 可惜equals默认是比较内存地址! 所以还要重写equals方法,保证equals方法是在比较内容!
f. HashSet利用的就是哈希算法,就是利用空间换取时间!
g. 3句话
i. 两个对象,哈希码不同,内容一定不同
ii. 两个对象,哈希码相同,内容不一定相同
iii. 两个对象,内容相同,哈希码一定相同
(联想宿舍)
*注:HahsSet 在jdk1.6 jdk1.7中的数据结构. jdk1.8中的数据结构(待补充)
HashMap扩容:
HashMap维护了一个Node(可以形成链表)类型的数组table。 *注:初始容量和扩容,都是针对map维护的table而言的。 1.存放数据时,会先根据元素的key的hash值计算(
ConcurrentHashMap分段锁(补充)
1.jdk1.8之前采用分段锁:ConcurrentHashMap维护了一个segment数组,里面是一个个HashEntry(链表)。而锁是加载segment上的,各segment间相互独立 2.jdk1.8后,ConcurrentHashMap去掉了Segment数组,锁直接加载table中各元素(node/treeify)的第一个元素(node)上,使锁粒度更细 扩容/重散列



