2021.2.8随笔

2021.2.8随笔

1.Queue

队列

Queue接口

(1)它是 Collecton 的一个队列子接口(定义了队列的概念)

(2)Queue 实现不允许插入 null 元素(LinkedList 除外)

// 如果使用 queue 定义的 poll 方法在队列中删除元素

// 如果队列中已经没有元素可以删除,那么会返回一个 null 值作为标记

Deque

(1)它是 queue 的一个子接口,它是双端队列子接口

(2)不仅可以作为双端队列使用,还可以充当一个普通队列和栈

(3)不允许存储 null

ArrayDeque

(1)它是双端队列的数组实现,

(2)底层是个数组, 是一个循环存储的数组

(3)默认初始容量(16), 扩容机制: 2倍

(4)有序, 允许重复元素, 不允许 null( poll 无元素可删除的时候, 返回值是null, 为了避免混淆)

(5)线程不安全

BlockingQueue

(1)它是 queue 接口的阻塞队列接口

(2)阻塞队列:限定容量队列,如果队列满了,阻塞添加线程,如果队列空了阻塞删除线程

(3)不允许null

(4)阻塞方法:

Put(): 添加方法, 没有位置可以添加, 线程阻塞, 当有位置可以添加的时候, 唤醒添加阻塞线程
Take(): 删除方法, 阻塞

Offer(e,  time,  unit)//  添加的元素,   时间,   时间单位
// 如果本身有存储空间, 直接添加, 如果没有添加的空间, 在多少时间内是阻塞的,  超过阻塞时间, 会转化为特殊值情况

Poll(time, unit)//  
// 如果有元素可以出队列, 直接出, 如果没有元素可以出队列, 等待, 知道超时, 转化为特殊值情况

2.Map

Map 接口

(1)Map是Map集合体系的顶级接口

(2)Map所存储的数据, key-value结构的数据, 键值对

(3)Map的key不允许’’重复’’:

键值对

​ Key-Value 结构的数据,一个 Key 对应着一个 Value

Key-value 数据具有自我描述性( 用 key 来描述 value)

api

这条最重要。使用频率最高。

V get(Object key)

返回指定键所映射的值;如果此映射不包含该键的映射关系,则返回 null。

void clear() 
          从此映射中移除所有映射关系(可选操作)。 
 boolean equals(Object o) 
          比较指定的对象与此映射是否相等。 
 int hashCode() 
          返回此映射的哈希码值。 
 boolean isEmpty() 
          如果此映射未包含键-值映射关系,则返回 trueint size() 
          返回此映射中的键-值映射关系数。 
		  
		 

 V put(K key, V value) 
          将指定的值与此映射中的指定键关联(可选操作)。 
 void putAll(Map<? extends K,? extends V> m) 
          从指定映射中将所有映射关系复制到此映射中(可选操作)。 
 V remove(Object key) 
          如果存在一个键的映射关系,则将其从此映射中移除(可选操作)。


boolean containsKey(Object key) 
          如果此映射包含指定键的映射关系,则返回 trueboolean containsValue(Object value) 
          如果此映射将一个或多个键映射到指定值,则返回 true。 
	

	
 Set<Map.Entry<K,V>> entrySet() 
          返回此映射中包含的映射关系的 Set 视图。 
 Set<K> keySet() 
          返回此映射中包含的键的 Set 视图。 
 Collection<V> values() 
          返回此映射中包含的值的 Collection 视图。

3.HashMap

最最重要的来了!!!!!!

(1)hashmap的底层结构 : 数组 + 链表 + 红黑树 (jdk 1.8)

(jdk1.8之前: 没有红黑树, 就是数组 + 单链表)

(2)hashmap底层维护了一个数组

(3) 数组默认初始容量16 , 数组扩容机制: 扩为原来的2倍, 默认的加载因子是0.75

(4)无序

(5)不允许重复的key: 详谈

(6)允许存储null键, 0

(7)线程不安全

(8)Hashmap能存储的元素数量 < 底层数组长度 * 加载因子的

(9)hashmap怎么判断重复的问题:

// (hash是否一样 && (key直接相等 || key相equals ))

Hash = (h = key.hashCode()) ^ (h >>> 16)

程序题:
/*
"aababcabcdabcde",获取字符串中每一个字母出现的次数
要求结果:a(5)b(4)c(3)d(2)e(1)
 */
public class work1 {
    public static void main(String[] args) {
        HashMap<Character, Integer> hashMap = new HashMap<>();
        String s = "aababcabcdabcde";
        for (char s1 : s.toCharArray()) {
            Integer i = hashMap.get(s1);
            if (i == null) hashMap.put(s1, 1);
            if (i != null) {
                i++;
                hashMap.put(s1, i);
            }
        }
        System.out.println(hashMap.keySet());
        System.out.println(hashMap.values());
    }
}
/*
给定一个整数数组和一个目标值,找出数组中和为目标值的两个数, 返回它们的索引。
   你可以假设每个输入只对应一种答案,且同样的元素不能被重复利用。

比如:nums = [2, 7, 11, 15], target = 9.  
             因为 nums[0] + nums[1] = 2 + 7 = 9. 所以返回 [0, 1].
 */
public class work2 {
    public static void main(String[] args) {
        int[] nums = {2, 7, 11, 15};
        int target = 9;
        System.out.println(findTarget(nums, target));

    }

    //    public static String findTarget(int[] nums, int target) {
//        int i, j = 0;
//        for (i = 0; i < nums.length; i++) {
//            for (j = i + 1; j < nums.length; j++) {
//                if (nums[i] + nums[j] == target && i != j) {
//                    return Arrays.toString(new int[]{i, j});
//                }
//            }
//        }
//        return null;
//        System.out.println(hashMap.keySet());
//        System.out.println(hashMap.values());
//}
    public static String findTarget(int[] nums, int target) {
        Map<Integer, Integer> hashMap = new HashMap<>();
        for (int i = 0; i < nums.length; i++) {
            hashMap.put(nums[i], i);
        }
        for (int i = 0; i < nums.length; i++) {
            int a = target - nums[i];
            if(hashMap.containsKey(a)){
                return "["+hashMap.get(nums[i])+","+hashMap.get(a)+"]";
            }
        }
        return null;
    }
}
还有一些源码分析

ArrayList 原码分析

//        1, 它是双端队列的数组实现,
//        2, 底层是个数组,  是一个循环存储的数组
//        3,  初始容量,  扩容机制
//        4,  有序(它是队列  线性表  线性表必定有序),
//            允许重复元素, 不允许null(poll无元素可删除的时候, 返回值是null, 为了避免混淆)
//        5, 线程不安全
        ArrayDeque<String> deque = new ArrayDeque<>();
class ArrayDeque{
    
    
    transient Object[] elements;// ArrayDeque 的底层数组
    
    public ArrayDeque() {
        elements = new Object[16];
    }
    
     public boolean add(E e) {
        addLast(e);
        return true;
    }
    
    public void addLast(E e) {
        if (e == null) throw new NullPointerException();
        
        elements[tail] = e;
        if ( (tail = (tail + 1) & (elements.length - 1)) == head)
            doubleCapacity();// 扩容方法
    }
    
    private void doubleCapacity() {
        assert head == tail;
        int p = head;
        int n = elements.length;
        int r = n - p; // number of elements to the right of p
        int newCapacity = n << 1;
        if (newCapacity < 0)
            throw new IllegalStateException("Sorry, deque too big");
        Object[] a = new Object[newCapacity];
        System.arraycopy(elements, p, a, 0, r);
        System.arraycopy(elements, 0, a, r, p);
        elements = a;
        head = 0;
        tail = n;
    }
}
HashMap的源码分析
//        2, hashmap底层维护了一个数组
        HashMap<String, String> map = new HashMap<>();
		map.put("zs", "18");
//        3, 数组初始容量16 , 数组扩容机制
//        4, 无序
//        5, 不允许重复的key: 
//        6, 允许存储null键, 0
//        7, 线程不安全
class HashMap{
    
   transient Node<K,V>[] table;// hashmap底层所维护的数组, 是一个Node类型的数组
    
   static final float DEFAULT_LOAD_FACTOR = 0.75f;
   final float loadFactor;// 加载因子(饱和度)
    
    public HashMap() {
        this.loadFactor = DEFAULT_LOAD_FACTOR;
    }
    
    //              zs      18
    public V put(K key, V value) {
        
        return putVal(  hash(key)  , key, value, false, true);
    }
    //                             zs
    static final int hash(Object key) {
        int h;
        // key =  null  ---> 0
        // key != null ----> 
        // h >>> 16: 为什么要移动它, 又运算
        // hash希望尽可能的散列
        // 010101010010101
        // 0000000 0101010
        //  这个操作就是为了让key充分散列
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }
    
    //               key的hash值  zs   18
    final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) {
        
        
        Node<K,V>[] tab; // 数组
        Node<K,V> p; // 结点
        int n,i;
        
        // tab = table:  table?就是hash的底层数组
        // tab = null
        if ((tab = table) == null || (n = tab.length) == 0)
            
            // tab = resize(): 扩容方法
            // n = 16
            n = (tab = resize()).length;
        
        // i = (n - 1) & hash:  取模
        // tab[i] :  key值经过hash计算, 又经过取模之后的对应数组下标位置
        // p =  tab[i]
        if ((p = tab[i = (n - 1) & hash]) == null)
            // 如果这个散列位置, 没有内容, 存进去
            tab[i] = newNode(hash, key, value, null);
        else {
          
    }
   Node<K,V> newNode(int hash, K key, V value, Node<K,V> next) {
        return new Node<>(hash, key, value, next);
    }
   static class Node<K,V> implements Map.Entry<K,V> {
        final int hash;// hash值
        final K key;// key
        V value;// value
        Node<K,V> next;// 下一个结点的指向
    }
      
    int threshold;// 标记阈值 = 数组长度 * 加载因子
    static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
        
     final Node<K,V>[] resize() {
         //  oldTab = table: 底层数组 , 此时此刻null
        Node<K,V>[] oldTab = table;
         // oldCap = 0;  旧容量0
        int oldCap = (oldTab == null) ? 0 : oldTab.length;
         // oldThr = threshold = 0:  阈值是0
        int oldThr = threshold;
         // 新长度, 新阈值
        int newCap, newThr = 0;
         
         // 
        if (oldCap > 0) {
          
        }
        else if (oldThr > 0) // initial capacity was placed in threshold
           
        else {              
            // newCap =  16
            newCap = DEFAULT_INITIAL_CAPACITY;
            // newThr =  0.75 * 16 = 12
            newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
        }
         
        if (newThr == 0) {
          
        }
         // threshold = 12
        threshold = newThr;
        
         // 创建一个数组: 16长度数组
        Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];
         // table = 16长度数组
        table = newTab;
  } 
}
HashMap 的扩容:的源码分析
class HashMap{
    
     transient Node<K,V>[] table;// hashmap底层所维护的数组, 是一个Node类型的数组
     int size; // 这个hashmap存储的键值对数目
    
     final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict) {
        Node<K,V>[] tab; Node<K,V> p; int n, i;
        
         // ......
         // 上面的逻辑处理添加元素
         
        ++modCount;
        if (++size > threshold)
            resize();
        afterNodeInsertion(evict);
        return null;
    }
    
   static final int MAXIMUM_CAPACITY = 1 << 30;
    
    final Node<K,V>[] resize() {
        // oldTab = table;// 长度为16的数组
        Node<K,V>[] oldTab = table;
       
        // oldCap = 16// 旧数组容量
        int oldCap = (oldTab == null) ? 0 : oldTab.length;
        // oldThr = 12// 旧阈值
        int oldThr = threshold;
        // 新长度, 新阈值
        int newCap, newThr = 0;
        
        
        if (oldCap > 0) {
            if (oldCap >= MAXIMUM_CAPACITY) {
              
            }
            // newCap = 2旧容量 = 32
            else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
                     oldCap >= DEFAULT_INITIAL_CAPACITY)
                // newThr = 2旧阈值 = 24
                newThr = oldThr << 1; 
        }
        else if (oldThr > 0) 
          
        else {    
          
        }
        if (newThr == 0) {
          
        }
        
        // threshold = 24
        threshold = newThr;
        // 创建了一个长度为32的数组
        Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];
        // 把这个数组, 复制给底层数组
        table = newTab;
  }
}
HashMap源码分析: 重复元素

到底什么是重复元素

class HashMap{
    
     final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict) {
        Node<K,V>[] tab; Node<K,V> p; int n, i;
        if ((tab = table) == null || (n = tab.length) == 0)
            n = (tab = resize()).length;
        if ((p = tab[i = (n - 1) & hash]) == null)
            // 散列的位置没有元素的逻辑
            tab[i] = newNode(hash, key, value, null);
        else {
            // 散列位置必定有元素
            
            Node<K,V> e; 
            K k;
            
            // (h = key.hashCode) ^ (h >>> 16): 有可能导致, 两个完全不同的对象hash值一样
            // p.hash == hash :  1, 两个key-value数据的, hash值是否一样
            // (k = p.key) == key || (key != null && key.equals(k))
            // key是否直接相等 或者 相equals
            
            // (hash是否一样   &&   (key直接相等 ||  key相equals  ))
            // 如果判断条件为真:  把新值 替换 旧值
            if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k))))
                e = p;
            else if (p instanceof TreeNode)
                e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
            else {
                for (int binCount = 0; ; ++binCount) {
                    if ((e = p.next) == null) {
                        p.next = newNode(hash, key, value, null);
                        if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                            treeifyBin(tab, hash);
                        break;
                    }
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        break;
                    p = e;
                }
            }
            if (e != null) { // existing mapping for key
                V oldValue = e.value;
                if (!onlyIfAbsent || oldValue == null)
                    e.value = value;
                afterNodeAccess(e);
                return oldValue;
            }
        }
        ++modCount;
        if (++size > threshold)
            resize();
        afterNodeInsertion(evict);
        return null;
    }
    
}
HashMap的源码分析: toString()
class HashMap extends AbstractMap{
  
}
class AbstractMap{
        public String toString() {
                Iterator<Entry<K,V>> i = entrySet().iterator();
                if (! i.hasNext())
                    return "{}";

                StringBuilder sb = new StringBuilder();
                sb.append('{');
                for (;;) {
                    Entry<K,V> e = i.next();
                    K key = e.getKey();
                    V value = e.getValue();
                    sb.append(key   == this ? "(this Map)" : key);
                    sb.append('=');
                    sb.append(value == this ? "(this Map)" : value);
                    if (! i.hasNext())
                        return sb.append('}').toString();
                    sb.append(',').append(' ');
                }
            }
    
    
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值