目录
我们为什么要用到集合中的迭代器
List实现类的循环遍历
Set集合
HashSet
TreeSet
Map
Hashmap
Treemap
Hashtable
map的遍历方式
Collections的一些静态方法
我们为什么要用到集合中的迭代器
List实现类的循环遍历
如图我们对arraylist中加入了三个相同的“a”时,使用for循环遍历删除会发现有漏网之鱼,为什么会出现这种现象呢?因为集合arraylist在删除时不会和数组一样不动,而是将后面的元素全部向前移动,这导致了i++之后变成了1删除了【a,a】删除了第三个"a",但是第二个“a”被保留了下来.
如图我们使用了增强for循环,这时对for循环的一种包装,我们在使用时会出现异常报错,在使用增强for循环时不可以进行增添或删除,所以我们不能用增强for循环。
如图我们可以显而易见的看到使用迭代器的方法将“a”全部删除了,这主要是由于迭代器内部有一个cursor(指针)从0开始遇到next()自动加一 遇到remove()自动减一,简而言之就是拿到先拿到第0个元素,然后指针向后移动一个,如果remove()则删除第0个元素,指针减一.可以debug试试.
以上三个图就是为什么使用迭代器的原因。
这是list迭代器 在arraylist linklist vector才可以用 功能更加丰富.
Set集合
Set接口:不重复元素、无索引
List接口:可重复、有索引(linklist也有存在node里了)
HashSet
hashset:哈希无序.
如何判断hashset中元素重复?
答:可以用equals来判断元素是否重复,但是equals底层实现在String类中是通过一个字符一个字符比较的这样的方法太慢了.所以我们在添加元素时底层会用hashCode()和equals()两种方法,先通过哈希值比较是否相等,用hash值比较时速度是很快,但是hash值是不安全不可靠的(有可能内容不同但是hash值相同),所以我们先判断哈希值是否相等,如果不相等直接pass,如果相等则为了安全考虑在使用equals()来逐个比较.既提高了效率又保证了安全.
如果将学生对象存储到hashSet中又该如何判断呢?
根据上一问的回答可知我们先判断hashCode()是否相等,hashCode()是Object类中定义的方法,所以创建的student类默认是具有hashCode()方法,但是Object中的hashCode()方法是返回内存地址如果通过new创建一个对象的话,则不管内容如何他们的内存地址都不相同。所以我们需要重写hashcode()方法和equals()方法。注意:从源码中可以得知时第二条重复数据将第一条数据覆盖了,而不是没添加进来.
重写hashcode和equals方法
结果显示则只有一条101 张三.
TreeSet
底层是树型结构,添加进来的元素可以排序(有序的,不是添加顺序,是元素的自然顺序)
我们如果使用普通的二叉树存储的话,遇到数据递增的情况则会出现如下图
这和链表就没什么区别了,我们用二叉树主要是能降低高度查找更快。
所以底层一般使用红黑树,递增是会进行旋转.
hashset中又是如何实现自然排序的呢?
答:和hashset的逻辑一样,不过是需要实现Comparable接口并重写compareTo()方法比较.
如果compareTo()的返回值为0则表示相等不会再添加对象到集合中去.
注意Comparable<Student>这个泛型要写,不然comparaTo方法中的参数类型就是Object类型还要向下转型。
Map
Hashmap
hashmap:无序 键不同(后键覆盖前键) 值可以相同
hashset底层用的就是new hashmap()将值put( value,默认值)放到key列里面。
hashmap中有 map.values()方法拿到所有的value返回一个Collection<>中,也又keySet()方法拿到所有key放到Set<>集合中。
Hashmap底层的三种结构:
1.hash数组(锁定元素位置node<k,v>[ ])扩容为原来的2倍,阈值为0.75(数组被使用到0.75时就会扩容)
2.链表(存储多个元素node(key,val))
3.红黑树(存储多个元素)
添加元素时,先计算元素hash值%数组长度(实际源码中时按位与hash值)得到元素位置,我们在存储时在同一个位置上使用链表的长度过长时(源码中长度>=8时且源码中想要创建红黑树还有一个条件是数组的长度需要大于等于64否则resize()对数组扩容会打乱原有链表排序)查询效率降低,这时我们将链表变为红黑树来提高查询效率。
这个图是我用smileNicky这个博主的图片 在扩容时的机制,源码也是这个意思.
Treemap
Treemap中的key 需要又comparable接口实现comparaTo方法
总的来说Tree和hash去重一个是compara去重一个是hashcode加equals去重
Hashtable
和hashmap底层相同 但是线程安全
和hashmap相比key不能为null,value也不能为null。
map的遍历方式
方式一:使用keyset集合拿到key值 增强for循环或者用迭代器遍历都可以
第二种也是map遍历最常用的方法可以拿到key也可以拿到value
entry是我们在用map中的一个内部类添加元素时维护的将键值对放到entry里面更方便遍历.
Collections的一些静态方法
类型.....参数名,可变长度参数,例如test(1,2,3,4) public static void test(int....a).
一个参数列表中只能有一个可变长度参数,而且必须放到末尾(int a,int....b)
Collections.addAll(arraylist,3,4,5,6)把3 4 5 6添加到arralist中
Collections.sort(arraylist)对集合进行排序
Collections.binarySearch(arraylist,1)排序后进行二分查找法找值
Collections.swap(arraylist,0,4)把第0个位置和第四个位置交换
Collections.copy(arraylist,arraylist1)把后面的集合元素复制到前面,前提是前面的集合长度必须大于后面,会把相同位置的元素覆盖成arraylist1中的元素.
Collections.fill(arraylist,0)将0填满数组
Collections.reverse(arraylist)逆序,也可以用迭代器ListIterator每次打印上一个元素
Collections.shuffle(arraylist)随即打乱集合