LinkedList 源码学习

LinkedList是一个实现了List接口和Deque接口的双端链表。 LinkedList底层的链表结构使它支持高效的插入和删除操作,另外它实现了Deque接口,使得LinkedList类也具有队列的特性; LinkedList不是线程安全的,如果想使LinkedList变成线程安全的,可以调用静态类Collections类中的synchronizedList方法:

List list=Collections.synchronizedList(new LinkedList(...));

import java.util.Iterator;
import java.util.LinkedList;

public class test2 {
    public static void main(String[] args) {
        LinkedList<Integer>linkedList=new LinkedList<Integer>();
        linkedList.addFirst(0);
        linkedList.add(1);
        linkedList.add(2,2);
        linkedList.addLast(5);
        /************************** Search操作 ************************/
        System.out.println("直接输出:"+linkedList);
        System.out.println("getFirst()获得第一个元素:"+ linkedList.getFirst());
        System.out.println("removeFirst()删除第一个元素并返回: " + linkedList.removeFirst()); // 移除并返回此列表的第一个元素
        System.out.println("After remove:" + linkedList);
        System.out.println("contains判断是否存在"+linkedList.contains(1));
        System.out.println("该linkedlist的大小"+linkedList.size());
        System.out.println("-----------------");
        linkedList.set(1,3);
        System.out.println("After set(1,3):"+linkedList);
        System.out.println("get(1)要获得指定位置的元素"+linkedList.get(1));
        System.out.println("-------------------");
        linkedList.add(3);
        System.out.println("indexof(3):"+linkedList.indexOf(3));
        //返回第一个3的索引
        System.out.println("lastindexof(3)"+linkedList.lastIndexOf(3));
        /************************** Queue操作 ************************/
        System.out.println("-----------------------------------------");
        System.out.println("获取但不移除列表的头:"+linkedList.peek());
        System.out.println("element():"+linkedList.element());
        linkedList.poll(); // 获取并移除此列表的头
        System.out.println("After poll():" + linkedList);
        linkedList.remove();
        System.out.println("After remove():" + linkedList); // 获取并移除此列表的头
        linkedList.offer(4);
        System.out.println("After offer(4):" + linkedList); // 将指定元素添加到此列表的末尾
        /************************** Deque操作 ************************/
        System.out.println("-----------------------------------------");
        linkedList.offerFirst(2); // 在此列表的开头插入指定的元素
        System.out.println("After offerFirst(2):" + linkedList);
        linkedList.offerLast(5); // 在此列表末尾插入指定的元素
        System.out.println("After offerLast(5):" + linkedList);
        System.out.println("peekFirst(): " + linkedList.peekFirst()); // 获取但不移除此列表的第一个元素
        System.out.println("peekLast(): " + linkedList.peekLast()); // 获取但不移除此列表的第一个元素
        linkedList.pollFirst(); // 获取并移除此列表的第一个元素
        System.out.println("After pollFirst():" + linkedList);
        linkedList.pollLast(); // 获取并移除此列表的最后一个元素
        System.out.println("After pollLast():" + linkedList);
        linkedList.push(2); // 将元素推入此列表所表示的堆栈(插入到列表的头)
        System.out.println("After push(2):" + linkedList);
        linkedList.pop(); // 从此列表所表示的堆栈处弹出一个元素(获取并移除列表第一个元素)
        System.out.println("After pop():" + linkedList);
        linkedList.add(3);
        linkedList.removeFirstOccurrence(3); // 从此列表中移除第一次出现的指定元素(从头部到尾部遍历列表)
        System.out.println("After removeFirstOccurrence(3):" + linkedList);
        linkedList.removeLastOccurrence(3); // 从此列表中移除最后一次出现的指定元素(从头部到尾部遍历列表)
        System.out.println("After removeFirstOccurrence(3):" + linkedList);

        /************************** 遍历操作 ************************/
        System.out.println("-----------------------------------------");
        linkedList.clear();
        System.out.println(linkedList);
        for (int i=0;i<100000;i++){
            linkedList.add(i);
        }
        //迭代器遍历
        long start = System.currentTimeMillis();
        System.out.println(start);
        Iterator<Integer>iterator=linkedList.iterator();
        while (iterator.hasNext()){
            iterator.next();
        }
        long end=System.currentTimeMillis();
        System.out.println("iterator时间差:"+(end-start)+"ms");
        //顺序遍历(随即遍历)
        start=System.currentTimeMillis();
        for (int i=0;i<linkedList.size();i++){
            linkedList.get(i);
        }
        end=System.currentTimeMillis();
        System.out.println("for循环时间差:"+(end-start)+"ms");

        // 另一种for循环遍历
        start = System.currentTimeMillis();
        for (Integer i : linkedList)
            ;
        end = System.currentTimeMillis();
        System.out.println("for2:" + (end - start) + " ms");

        //通过pollFirst或者pollLast来遍历LinkedList
        LinkedList<Integer>temp1=new LinkedList<>();
        temp1.addAll(linkedList);
        start=System.currentTimeMillis();
        while (temp1.size()!=0){
            temp1.pollFirst();
        }
        end = System.currentTimeMillis();
        System.out.println("pollFirst()或pollLast():" + (end - start) + " ms");

        // 通过removeFirst()或removeLast()来遍历LinkedList
        LinkedList<Integer> temp2 = new LinkedList<>();
        temp2.addAll(linkedList);
        start = System.currentTimeMillis();
        while (temp2.size() != 0) {
            temp2.removeFirst();
        }
        end = System.currentTimeMillis();
        System.out.println("removeFirst()或removeLast():" + (end - start) + " ms");

    }
}

java面经

Java 集合类

类的属性

public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable {
    // 序列号
    private static final long serialVersionUID = 362498820763181265L;    
    // 默认的初始容量是16
    static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;   
    // 最大容量
    static final int MAXIMUM_CAPACITY = 1 << 30; 
    // 默认的填充因子
    static final float DEFAULT_LOAD_FACTOR = 0.75f;
    // 当桶(bucket)上的结点数大于这个值时会转成红黑树
    static final int TREEIFY_THRESHOLD = 8; 
    // 当桶(bucket)上的结点数小于这个值时树转链表
    static final int UNTREEIFY_THRESHOLD = 6;
    // 桶中结构转化为红黑树对应的table的最小大小
    static final int MIN_TREEIFY_CAPACITY = 64;
    // 存储元素的数组,总是2的幂次倍
    transient Node<k,v>[] table; 
    // 存放具体元素的集
    transient Set<map.entry<k,v>> entrySet;
    // 存放元素的个数,注意这个不等于数组的长度。
    transient int size;
    // 每次扩容和更改map结构的计数器
    transient int modCount;   
    // 临界值 当实际大小(容量*填充因子)超过临界值时,会进行扩容
    int threshold;
    // 加载因子
    final float loadFactor;
}

介绍下 HashMap 的原理,源码,扩容机制,加载因子等内容

loadFactor加载因子

loadFactor加载因子是控制数组存放数据的疏密程度,loadFactor越趋近于1,那么 数组中存放的数据(entry)也就越多,也就越密,也就是会让链表的长度增加,loadFactor越小,也就是趋近于0,数组中存放的数据(entry)也就越少,也就越稀疏。

loadFactor太大导致查找元素效率低,太小导致数组的利用率低,存放的数据会很分散。loadFactor的默认值为0.75f是官方给出的一个比较好的临界值。

给定的默认容量为 16,负载因子为 0.75。Map 在使用过程中不断的往里面存放数据,当数量达到了 16 * 0.75 = 12 就需要将当前 16 的容量进行扩容,而扩容这个过程涉及到 rehash、复制数据等操作,所以非常消耗性能。
介绍下 ConcurrentHashMap 的分段锁
解释下哈希碰撞,当两个元素哈希值相等时,它是怎么一个操作原理和过程呢?
Java 多线程

了解过线程(Thread)吗?
说一下实现线程有哪几种方法?
在实际场景中有使用过 Callable 吗?
平时一般使用哪种类型的线程池?
假设你的 CPU 是 2 核或者是 4 核的,如果采用固定大小的线程池,那你会固定多少个线程?
说一下对 synchronized 关键字的了解
平时在实际场景中是如何使用这个关键字的?
一般是将这个关键字加在方法上还是代码体上?
平时在项目中是有没有使用过 synchronized,是如何是用的?
说一下对 volatile 关键字的了解
volatile 关键字会禁止指令重排序吗?
平时有使用过 volatile 关键字吗?
有了解过 volatile 的底层原理吗?比如说在操作系统中,在内存中的过程
AQS 了解吗?简单讲一下
JVM

说一下你对 JVM 的了解
了解 JVM 的内存分配吗?
比如 private String a = “abc” 语句,定义了一个字符串常量,它是存储在哪里?
说一下堆细分成哪几部分?
比如 new String(“字符串”) 这种方式,常量的值是放到哪一区域?新生代还是老年代?
如果是大对象的话是优先放到老年代,对吧?
说一下一个对象从 Eden 区到 From Survivor ,再到 To Survivor 区,再到老年代的过程
如何判断一个对象死亡?
说一下四种引用类型
像我们日常当中是使用哪一个引用?
日常中使用强引用的时候会导致 gc 无法回收,虚拟机内存从而会抛出一个什么异常或错误?
Error 和 Exception 的区别?
如何判断一个类是无用的类?
数据库

说一下你对索引的理解,优缺点等
平时有使用过联合索引吗?
比如说有 a,b,c,d,e,f,g 这些字段,把 b,c,d 三个字段做一个索引,有没有这样使用过?或者说当我这样去使用的时候,为了使索引生效,我应该怎样去查询?比如当我有 b,c,d 三个字段的值的时候可以生效,如果只有 b,c 或 c,d 等字段的值时可以让联合索引生效吗?
如果使用模糊查询,那这个索引还能生效吗?
如果是前后都有 % ,它能生效吗?
除了 % 能让索引失效,还有哪些能让索引失效?
平时在设计数据库表的一些基础字段时是如何设计的?
说一下事务的隔离级别
框架

有看过 Spring 的 IOC 和 AOP 的源码吗?
在日常使用中有没有了解过 xml 配置文件,使用注解之类的?

Node节点类源码:

// 继承自 Map.Entry<K,V>
static class Node<K,V> implements Map.Entry<K,V> {
       final int hash;// 哈希值,存放元素到hashmap中时用来与其他元素hash值比较
       final K key;//键
       V value;//值
       // 指向下一个节点
       Node<K,V> next;
       Node(int hash, K key, V value, Node<K,V> next) {
            this.hash = hash;
            this.key = key;
            this.value = value;
            this.next = next;
        }
        public final K getKey()        { return key; }
        public final V getValue()      { return value; }
        public final String toString() { return key + "=" + value; }
        // 重写hashCode()方法
        public final int hashCode() {
            return Objects.hashCode(key) ^ Objects.hashCode(value);
        }

        public final V setValue(V newValue) {
            V oldValue = value;
            value = newValue;
            return oldValue;
        }
        // 重写 equals() 方法
        public final boolean equals(Object o) {
            if (o == this)
                return true;
            if (o instanceof Map.Entry) {
                Map.Entry<?,?> e = (Map.Entry<?,?>)o;
                if (Objects.equals(key, e.getKey()) &&
                    Objects.equals(value, e.getValue()))
                    return true;
            }
            return false;
        }
}

在这里插入图片描述

import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Set;

public class test3 {
    public static void main(String[] args) {
        HashMap<String,String> map=new HashMap<>();
        // 键不能重复,值可以重复
        map.put("san", "张三");
        map.put("si", "李四");
        map.put("wu", "王五");
        map.put("wang", "老王");
        map.put("wang", "老王2");// 老王被覆盖
        map.put("lao", "老王");
        System.out.println("-------直接输出hashmap:-------");
        System.out.println(map);
        /*
        遍历hashmap
         */
        System.out.println("-----foreach获取Map中所有的键--------");
        Set<String> keys=map.keySet();
        for (String key:keys){
            System.out.print(key+" ");
        }
        System.out.println();
        // 2.获取Map中所有值
        System.out.println("-------foreach获取Map中所有的值:------");
        Collection<String> values = map.values();
        for (String value : values) {
            System.out.print(value+"  ");
        }

        System.out.println("--------得到key的同时也得到值----------");
        Set<String> keys2=map.keySet();
        for (String key:keys2){
            System.out.print(key+":"+map.get(key)+"  ");
        }

        Set ent=map.entrySet();

        Iterator it=map.keySet().iterator();
        while (it.hasNext()){
            String key=(String) it.next();
        }

        System.out.println("----------map的其他用法-------------");
        System.out.println("after map.size():"+map.size());
        System.out.println("after map.isEmpty():"+map.isEmpty());
        System.out.println(map.remove("san"));
        System.out.println("after map.remove():"+map);
        System.out.println("after map.get(si):"+map.get("si"));
        System.out.println("after map.containsKey(si):"+map.containsKey("si"));
        System.out.println("after containsValue(李四):"+map.containsValue("李四"));
        System.out.println(map.replace("si", "李四2"));
        System.out.println("after map.replace(si, 李四2):"+map);


    }
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值