容器
数组本身也是容器,是一个简单的线性序列,访问效率非常高。但是数组本身不够灵活,一开始就要定义数组的元素。
collection(集合/容器)
set无顺序不重复(hashSet),list有顺序可以重复(ArrayList,LinkedList)。
map 存放键值对。
泛型:贴标签,建立类型安全的集合,本质就是数据类型的参数化,告诉编译器在调用的时候必须传入参数类型。
List中的方法:addAll(Collection B):把B中所有的元素都加到A里面
removeAll(Collection B):移除本容器中和B容器中共有的元素。
retainAll(Collection B):移除A容器中AB容器中非交集的元素。
List:是有序的,可重复的容器。
有序:List中的每个元素都有索引标记。可以根据元素的索引标记(在List中的位置)访问元素,从而精确控制这些元素。
可重复:List允许加入重复的元素。更确切的讲,List通常允许满足e1.equals(e2)的元素重复加入容器。
List中常用的三种实现类:ArrayList、LinkedList和Vector。
ArrayList的底层实现是数组。
ArrayList中的add方法是一个重载的方法,可以在指定的位置插入一个数据。add(index,E);
remove(index):删除指定位置的元素。
set(index,E)将指定位置的数据设置为E,相当于修改替换。
get(index):获取索引地址的数据。
indexOf(Object o) 如果查到,返回索引第一次出现的位置,如果没有查到,返回-1。
lastIndexOf(Object o) 如果查到,返回索引最后一次出现的位置,如果没有查到,返回-1。
ArrayList
底层是数组的方式实现存储。特点是:查询效率高,增删效率低,线程不安全。我们一般使用它。
数组的长度是有限的,ArrayList是可以存放任意长度,底层自动扩容。定义一个更长的数组,老的复制到新的里面。默认长度是10,可以new ArrayList(size)来定义内部数组的长度。新长度等于老数组长度加老数组的一半
Old = Old+(Old>>1);
add与remove底层都是数组的拷贝,remove是自己拷贝自己,报后面的所有元素向前移动一个位置。
LinkedList
底层使用双向链表实现存储,特点是查询效率低,增删效率高,线程不安全。
双向链表也叫双链表,是链表的一种,没一个节点包含三部分,上一个节点、下一个节点、数据。
Vector
也是用数组实现的,但是相关方法都加了同步检查,因此“线程安全,效率低”。
建议:
需要多线程时用Vector
不存在线程安全的时候,查找多的用ArrayList,增删多的时候用LinkList。
Map
Map用来存储键值对,Map中存储的键值对是通过键来标识,所以键不能重复。如果重复,新的覆盖旧的。判断是否重复用的是Equals方法。
Map接口实现类有HashMap、TreeMap、HashTable、Properties等。
HashMap底层实现采用了哈希表,这是一种非常重要的数据结构。
哈希表的基本结构就是“数组+链表”。
数组:占用空间连续,寻址容易,查询速度快,但是增加删除的效率非常低。
链表:占用空间不连续。寻址困难,查询速度慢。但是增加和删除的效率非常高。
主要的存储结构是 Node(key value next hash),是一个单项列表。
每个节点Node 由key、value、next、hash四部分组成。
然后把节点放入Node[]数组中,数组中的每个元素都是一个链表。
hashMap的存储过程
1.先计算键对象的hashcode(),然后通过hash()算法计算出应该存储的位置【将hashcode与数组大小相除取余,余数就是节点存放的数组下标,后来改成了位运算,hashcode&(length-1)也是取余,但是长度必须是2的倍数。后来又进行了两次散列处理,是结果更加的散列。】
Jdk8中,当链表的长度大于8时,链表就转换为红黑树,增加了查询效率。
hashMap的取值过程
先计算键对象的hashcode,然后通过hash()算法算得hash值(node中的hash值)定位到存储的位置,然后通过Equals方法去找对应key进行比较,然后找到value从而找到准确的内容。
java规定:相同的对象的hashcode是相同的
扩容问题:hashMap数组桶的初始值是16,当元素达到数组桶的0.75倍时,将发生扩容,变成原来的2倍。扩容的本质是定义新的更大的数组,并将就数组内容挨个拷贝到新数组中。
JDK8将链表在大于8,数组总容量大于64 的情况下把链表变为红黑二叉树。
除了添加,其他效率都高了。
TreeMap
排序的情况下才使用TreeMap,TreeMap的底层是典型的红黑二叉树,每个节点都存储了本身数据、左节点、右节点、父节点、以及节点颜色。
遍历时按照key递增的方式进行排序。
Comparable接口
Comparable接口的方法中有一个compareTo方法 重写compareTo方法定义比较对象,返回值负数对应的是小于,正数是大于,0是等于。
class Emp implements Comparable<Emp> { int id; String name; double salary; public Emp(int id, String name, double salary) { super(); this.id = id; this.name = name; this.salary = salary; } @Override public String toString() { return "id:"+id+",name:"+name+",salary:"+salary; } @Override public int compareTo(Emp o) { //负数:小于,0:等于,正数:大于 if(this.salary>o.salary){ return 1; }else if(this.salary<o.salary){ return -1; }else{ if(this.id>o.id){ return 1; }else if(this.id<o.id){ return -1; }else{ return 0; } } } }
1、HashMap:线程不安全,效率高。允许key或value为null。
2、HashTable:线程安全,效率低。不允许key或value为null。
set接口
没有顺序,不可重复。只能遍历查找;不可重复指不允许加入重复的元素(新元素如果和Set中的某个元素通过equals()方法对比为true,则不能加入)。Set中只能放一个null元素,不能放入多个。
Set常见的实现类有:HashSet,TreeSet等,通产使用HashSet。
HashSet
HashSet也是采用的哈希算法实现的,底层实际用的是HashMap实现的(HashSet本质就是一个简化版的HashMap),因此,查询效率和增删效率都比较高。
HashSet就是一个hashMap,存储的值就是map的键,所以不能重复。
TreeSet
TreeSet的底层是TreeMap,也是用map的键进行set值的存储,也是按照元素递增的方式进行存储。自定义排序也用实现Comparable接口实现CompareTo方法。
Iterator迭代器
可遍历List Set Map
以hasNext和Next配合使用。
其中Map需要先用keySet获取键,然后迭代器遍历键的set获取值。或者使用entrySet直接获取Set<Entry<K,V>>然后进行遍历。
Collections工具类
对Set、List、Map进行排序、填充、查找元素的辅助方法。
void sort(List)对List容器内的元素进行排序,排序的规则是按照升序进行排序。自定义的类使用COmparable接口。
void shuffle(List) 随机排序 打乱顺序
void reverse(List)逆序排序 12345 --> 54321 132-->231
void fill(List,Object)用一个特定的对象重写整个List容器。
int binarySearch(List,Object)对于顺序的List容器,采用折半查找(二分法)的方法查找特定的对象。