Day07 java类集 :Collection的list和set Map

类集java.util.*

顶级接口 :Collection Map Ilerator

类集是java对数据结构的成熟实现,不用自己再去写了。

数组和链表的区别 (面试常考)

  • 数组存取(按下标查找)速度快,链表很慢
  • 数组需要事先知道长度,链表不需要
  • 数组空间通常有限制,需要大块连续内存块,链表是离散分配节点的,通过指针相连,空间无限制
  • 链表插入删除元素很快,无需移动
  • 链表的特点,只有一个前驱,只有一个后继

二叉树

  • 先序遍历:根左右
  • 中序遍历:左根右
  • 后序遍历:左右根

待补充:遍历顺序在算法题解题中有妙用。

红黑树

速度快,接近平衡树,查找叶子元素最少和最多次数不多于2倍。

Collection接口

单值存储。

为了区分集合中是否允许有重复元素,现在使用其子接口Listset

List

  • 都提供了Iterator方法,返回ListIterator实例。

  • 缓存后还需要取出来,直接让remove返回就可以。

  • set修改,add添加,都可以指定index

  • 允许重复

ArrayList Vector LinkedList
  • 构造方法有3种。(Collection<? extends E> o)可以根据迭代器返回的顺序构建包含指定元素的列表。
ArrayList
  • ArrayList发现存不了就会扩容

  • 其add方法只会返回true

  • 扩容:elementData=grow();grow返回的是Object[]

  • 扩容算法:方法重载,无参方法里返回有参grow,传一个最小容量(原容量+1)过去,根据旧数组和新长度创建新的数组并且给他复制进去,如下

  • 带参grow的内容:返回Arrays.copyOf(elementData,newCapacity(minCapacity));

  • 新长度怎么算:

private int newCapacity(int minCapacity){
    //旧容量
    int oldCapacity = elementData.length;
    int newCapacity = oldCapacity + (oldCapacity >> 1);//相当于除2,也就是旧+旧/2的长度
    if(newCapacity - minCapacity <= 0){
        //如果没成功,没增长 两种可能 1是0 2是溢出
        if(elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA)//如果为默认的空???第一次创建 没长度 默认为0
            return Math.max(DEFAULT_CAPACITY, minCapacity);//返回默认和传参中的最大值 第一次:0&1
        if(minCapacity < 0)
            //int最大值+1 溢出 符号位改变成为负数 突然联想到了银行家算法
            throw new OutOfMemoryError();
        return minCapacity;
    }
    //最大长度 检查是否比最大值小 Integer.MAX_VALUE-8
    return (newCapacity - MAX_ARRAY_SIZE <= 0)
        ? newCapacity
        : hugeCapacity(minCapacity);//如果比最大值还要大,会执行这个方法
}
/**
* 过大的长度
*/
private static int hugeCapacity(int minCapacity){
    //一直在传这个minCapacity
    if(minCapacity < 0) //说明溢出
        throw new OutOfMemoryError();
    return (minCapacity > MAX_ARRAY_SIZE)//是否要很大的长度
        ? Integer.MAX_VALUE
        : MAX_ARRAY_SIZE;
}
Vector
  • 线程安全

  • 这个类的iterator和listIterator方法返回的迭代器是快速失败的。

  • 构造方法有4个,两参的要传递指定初始容量和容量增量的

  • 扩容方法计算新容量时,如果增量大于0就加增量,否则直接加个旧长度,然后是同样的判断是否溢出等等

LinkedList

双向链表实现。特殊方法:

  • addFirst addLast
  • peek poll push等
  • 可以实现队列和栈

迭代器Iterator

Iterator<Integer> iterator = list.iterator();
while(iterator.hasNext()){
    //循环条件有下一个
    Integer i = iterator.next();//移动迭代器指针
    iterator.remove();//删除迭代器返回的最后一个元素,必须next获取之后才能删除
    hasPrevious();//往前走 但是需要先往下走才能往回
    iterator.add(100);//紧接在next()返回的元素之前 previous返回的元素之后插入,隐式游标之前插入 对next()调用不受影响,对previous调用将返回新插入的元素
    iterator.set(200);//    
}

总结:

  1. 判断hasNext()
  2. 获取next()

forEach 增强for循环

for(int a:arr){
	//
}

迭代数组或者集合(Collection)

Set

set是跟collection一样没有get,它不会包含重复元素,不保证顺序。

可以使用Iterator,forEach遍历

HashSet

散列存放。还是双值存储,放入的是元素和一个默认值。

add()方法可以返回true或false

TreeSet

采用有序二叉树存储。自然顺序。

  • 该类Iterator快速失败,遍历的是集合本身,记录遍历到哪个变量,如果有另外的线程要修改数据,那么迭代器出现异常。ConcurrentModificationException。

安全失败:失败不会出错,把集合复制了一份,遍历的是复制的那一份。

char A是65编码System.out.println((char)65);

如果想要自己设定顺序,重写comparator比较器,实现Comparable接口

static class Person implements Comparable<Person> {
//this和o进行比较,返回负数(this小于) 正数(this大于) 0(相等)
	@Override
	public int compareTo(Person o){
		if(this.age>o.age){
            return 1;
        }else if(this.age<o.age){
            return -1;
        }else{
            return 0;
        }
	}
}

set不允许相等。

Map

  • Map跟Collection是一个级别的。双值存储。

  • key不可重复

  • 遍历操作很麻烦

重要方法:

  • KeySet() 通过钥匙来找数据,把每个键拿出来

  • 是否存在 containsKey containsValue

  • values()返回包含的值的Collection形式

哈希表HashMap

动态数组+链表+红黑树

  • hashCode()返回int值
    • 调用对象的hashCode值跟数组的长度取余(默认长度16取余是0~15,得到下标)
    • 如果重复下标,链表
    • 如果哈希桶中链表长度已经到8还要加,转换为红黑树
    • 当哈希桶中的数据量减少到6时,从红黑树转换为链表
  • 初始桶数量16 散列因子0.75(如果已经75%存入数据,则扩容为原长度2倍)
源码分析
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;//默认初始化容量16
//put->putVal
public V put(K key, V value) {
    return putVal(hash(key), key, value, onlyIfAbsent:false, evict:true);//通过hash()方法计算key的hash值,键,值
}
//下标计算方式:tab[i=(n-1)&hash]结果就是拿hash值对n-1取余
  1. 调用put(key,value);

  2. 通过hash算法得到key的hash值

  3. 判断Node数组table是否为null或长度为0

  4. 调用resize()方法对table进行扩容|判断table[i]是否已有元素

  5. 如果已有,判断key是否重复

  6. 判断table[i]的类型是链表节点(如果=8(TREEIFY_THRESHOLD,转红黑树)还是红黑树节点 调用不同方法插入

  7. 在新节点插入后,modCount++,判断size是否大于临界值,如果是,调用resize()方法

遍历方法
for(String key:map.keySet()){
    String value = map.get(key);
}
for(String value:map.values()){
    System.out.println(value);
}
初始容量和负载因子

ConcurrentHashMap

在java.util.concurrent.*包里。

HashMap HashTable ConcurrentHashMap这几个容器的区别
  • HashMap 线程不安全 效率高
  • HashTable 线程安全 效率低 锁所有桶
  • ConcurrentHashMap 分段锁机制,线程安全,效率较高
    • 只有当操作同一下标的时候才锁

LinkedHashMap既在哈希表里又在双向链表里

hashCode()

result = 31 * result + (element == null? 0:element.hashCode());

如果修改对象但没put进去,就会导致hashCode不一样,就没法找到。

如果新增对象name和info是一样的,还要判断equals,所以也找不到。

jdk9中的集合新特性

创建固定长度的集合的便捷方法。

list set map

static <E> List<E> of(E e1, E e2, E e3)

List<String> list = List.of("xxx","xxx");

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值