面试-Java【之】HashMap原理,源码逐行分析,理论总结(变量、常量、数据结构、Node、TreeNode、初始化、添加、查询、更新、删除)

2023-10-27

1.源码分析

1.HashMap属性与变量(扩容因子、扩容阈值、结构转换阈值…)

 public class HashMap<K,V> extends AbstractMap<K,V>implements Map<K,V>, Cloneable, Serializable {
     
     //默认扩容的临界值(table大于此值时,进行扩容)
     static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
     //扩容临界值的最大值
     static final int MAXIMUM_CAPACITY = 1 << 30;

     //链表转红黑树的大小阈值(当链表长度大于8时,并且数组长度大于64时, 链表数据结构,转为红黑树)
     static final int TREEIFY_THRESHOLD = 8;
     //链表转红黑树的大小阈值(当链表长度大于8时,并且数组长度大于64时, 链表数据结构,转为红黑树)
     static final int MIN_TREEIFY_CAPACITY = 64;
     //红黑树转链表的阈值(当链表长度小于6,并且数组长度小于64时, 红黑树数据结构,转为链表)
     static final int UNTREEIFY_THRESHOLD = 6;

 	//当前扩容因子(扩容时的倍数),默认0.75f
     static final float DEFAULT_LOAD_FACTOR = 0.75f;

 	//数组(内部存储 Node链表节点,或者,TreeNode红黑树节点)
     transient Node<K,V>[] table;
     //扩容的临界值(table大于此值时,进行扩容),默认值 DEFAULT_INITIAL_CAPACITY
     int threshold;
 	//当前扩容因子(扩容时的倍数)
     final float loadFactor;
 }

2.Node(链表节点)

public class HashMap<K,V> extends AbstractMap<K,V>implements Map<K,V>, Cloneable, Serializable {

 static class Node<K,V> implements Map.Entry<K,V> {
     	//当前节点-hash
        final int hash;
     	//当前节点-key   
     	final K key;
    	//当前节点-value   
     	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;
        }
 }
}

3.TreeNode(红黑树节点)

public class HashMap<K,V> extends AbstractMap<K,V>implements Map<K,V>, Cloneable, Serializable {

   static final class TreeNode<K,V> extends LinkedHashMap.Entry<K,V> {
       	//父节点
        TreeNode<K,V> parent;  // red-black tree links
        //相邻左侧节点
       	TreeNode<K,V> left;
       	//相邻右侧节点
       	TreeNode<K,V> right;
       	//上一页 
       	TreeNode<K,V> prev;    // needed to unlink next upon deletion
        
       	TreeNode(int hash, K key, V val, Node<K,V> next) {
            super(hash, key, val, next);
        }
   }
}

4.初始化(new)

public class HashMap<K,V> extends AbstractMap<K,V>implements Map<K,V>, Cloneable, Serializable {
	
	//设置扩容因子,和,扩容临界值,并未初始化数组
    public HashMap(int initialCapacity, float loadFactor) {
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal initial capacity: " +
                                               initialCapacity);
        if (initialCapacity > MAXIMUM_CAPACITY)
            initialCapacity = MAXIMUM_CAPACITY;
        if (loadFactor <= 0 || Float.isNaN(loadFactor))
            throw new IllegalArgumentException("Illegal load factor: " +
                                               loadFactor);
       	//设置扩容因子,和,扩容临界值
        this.loadFactor = loadFactor;
        this.threshold = tableSizeFor(initialCapacity);
    }

    static final int tableSizeFor(int cap) {
        int n = cap - 1;
        n |= n >>> 1;
        n |= n >>> 2;
        n |= n >>> 4;
        n |= n >>> 8;
        n |= n >>> 16;
        return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
    }

	//设置扩容因子,和,扩容临界值,并未初始化数组
    public HashMap(int initialCapacity) {
        this(initialCapacity, DEFAULT_LOAD_FACTOR);
    }
	
	//无参构造函数,设置扩容临界值,并未初始化数组
    public HashMap() {
        this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
    }

	//设置扩容临界值,并,插入数据
    public HashMap(Map<? extends K, ? extends V> m) {
        this.loadFactor = DEFAULT_LOAD_FACTOR;
        putMapEntries(m, false);
    }
 }

5.插入、更新(put、putVal)

public class HashMap<K,V> extends AbstractMap<K,V>implements Map<K,V>, Cloneable, Serializable {

   	//key : 键
	//value : 值
	//hash(key) : 调用对象自身的 hash方法
	public V put(K key, V value) {
        return putVal(hash(key), key, value, false, true);
    }
    
	final V putVal(int hash, K key, V value, boolean onlyIfAbsent,boolean evict) {
       
        //tab:当前数组
        //i:数据在tab中的索引下标
        //p:在tab中,key对应的下标节点数据,也就是 tab[i]
        //n:tab长度
        Node<K,V>[] tab; Node<K,V> p; int n, i;

        //如果tab为空,执行初始化或扩容数组
        //resize() :初始化或扩容数组
        if ((tab = table) == null || (n = tab.length) == 0)
            n = (tab = resize()).length;
        
        //如果tab中当前位置没有数据,直接创建并插入节点
        //i是tab中,数据对应存放的位置: = (n - 1) & hash
        //p是tab中,数据对应存放的值
        if ((p = tab[i = (n - 1) & hash]) == null)
            tab[i] = newNode(hash, key, value, null);
        
        //如果位置上已经有数据,此时出现冲突
        else {
            
            //对比当前位置数据的Key,与将要插入的数据的Key,如果一致,直接替换数据  e = p;
            Node<K,V> e; K k;
            if (p.hash == hash &&
                ((k = p.key) == key || (key != null && key.equals(k))))
                e = p;
            
           	//如果Key不一致,判断是否为红黑树节点,是则插入数据
            else if (p instanceof TreeNode)
                e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
           
          	//如果Key不一致,也不是红黑树节点
            else {
                
                //循环比对当前链表内的Key
                //如果不存在,则直接插入,如果存在一致,则替换
                for (int binCount = 0; ; ++binCount) {
                   
                    //如果不存在,则直接插入
                    if ((e = p.next) == null) {
                        p.next = newNode(hash, key, value, null);
                        //如果循环次数,超过8次,则将数据结构转为红黑树
                        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();
        //在HashMap中这里是空实现
        afterNodeInsertion(evict);
        return null;
    }
 }

6.删除(remove、removeNode)

public class HashMap<K,V> extends AbstractMap<K,V>implements Map<K,V>, Cloneable, Serializable {

    //key:删除条件KEY
	public V remove(Object key) {
        //e:被删除的节点
        Node<K,V> e;
        return (e = removeNode(hash(key), key, null, false, true)) == null ?
            null : e.value;
    }
    
    final Node<K,V> removeNode(int hash, Object key, Object value,
                               boolean matchValue, boolean movable) {
       	//tab:当前数组
        //n:当前数组长度
        //index:key对应的在数组中的下标
		//p:key对应在数组中的数据 ,也就是tab[index]
        Node<K,V>[] tab; Node<K,V> p; int n, index;
        
        //如果tab不等于空,并且对应index下标位置有数据,则判断通过
        if ((tab = table) != null && (n = tab.length) > 0 &&
            (p = tab[index = (n - 1) & hash]) != null) {
           
          	 //node:将要被删除的节点
            Node<K,V> node = null, e; K k; V v;
            
             //继续判断,hash相同,key相同,则被删除节点就是当前下标数据,也就是 node=tab[index]
            if (p.hash == hash &&
                ((k = p.key) == key || (key != null && key.equals(k))))
                node = p;
            
            //如果当前位置Node节点不满足条件,则继续判断
            else if ((e = p.next) != null) {
                
                //如果当前节点是红黑树,则获取节点数据,赋值给node
                if (p instanceof TreeNode)
                    node = ((TreeNode<K,V>)p).getTreeNode(hash, key);
               
                //否则,循环从链表中读取,找到后,赋值给node
                else {
                    do {
                        if (e.hash == hash &&
                            ((k = e.key) == key ||
                             (key != null && key.equals(k)))) {
                            node = e;
                            break;
                        }
                        p = e;
                    } while ((e = e.next) != null);
                }
            }
           
            //判断被删除节点不为空,执行删除逻辑
            if (node != null && (!matchValue || (v = node.value) == value ||
                                 (value != null && value.equals(v)))) {
                
                //删除红黑树节点
                if (node instanceof TreeNode)
                    ((TreeNode<K,V>)node).removeTreeNode(this, tab, movable);
                
                //删除Node节点(将原有位置数据的引用,指向链表中下一个数据,实现删除逻辑)
                else if (node == p)
                    tab[index] = node.next;
                else
                    p.next = node.next;
                ++modCount;
                --size;
                afterNodeRemoval(node);
                return node;
            }
        }
        
        return null;
    }
 }

7.读取(get、getNode)

 public class HashMap<K,V> extends AbstractMap<K,V>implements Map<K,V>, Cloneable, Serializable {
    
    //e:读取结果
	public V get(Object key) {
        Node<K,V> e;
        return (e = getNode(hash(key), key)) == null ? null : e.value;
    }
	
    final Node<K,V> getNode(int hash, Object key) {
        
      	//tab:当前数组
        //n:当前数组长度
		//first:key对应在数组中的数据 , 也就是tab[index]
        //k:first的key
        Node<K,V>[] tab; Node<K,V> first, e; int n; K k;
        
        //数组不为空,并且first不等于空,继续执行
        if ((tab = table) != null && (n = tab.length) > 0 &&
            (first = tab[(n - 1) & hash]) != null) {
            
            //first的 hash与key 和 传入的一致,证明 first就是查询结果,直接返回
            if (first.hash == hash && // always check first node
                ((k = first.key) == key || (key != null && key.equals(k))))
                return first;
            
            //比对结果不一致,继续判断
            if ((e = first.next) != null) {
                
                //如果first位置的Node是红黑树,直接获取数据
                if (first instanceof TreeNode)
                    return ((TreeNode<K,V>)first).getTreeNode(hash, key);
                
                //如果first位置的Node是链表,遍历链表获取数据
                do {
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        return e;
                } while ((e = e.next) != null);
            }
            
        }
        return null;
    }
}

2.理论总结

1.核心:数组+ 链表或者红黑树

  • 核心:数组Node<K,V>[] table + 链表或者红黑树
  • 因为这种存储结构,所以,HashMap的查询效率高:第一次查询是 O(1) , 第二次是 O(n)
  • 1.初始化:new:确定 扩容因子 loadFactor 和 临界点 threshold,并没有初始化数组,初始化数组是在第一次查询数据时 resize()内实现的

2.put 操作:首次插入:无冲突情况

  • 2.put 操作:首次插入:无冲突情况
    • 1.计算KEY的Hash值 ; 例如 “a” 的HashCode 是 97
    • 2.判断临界点 threshold 是否扩容,更新临界点
    • 3.创建Node(链表结构) ,存放位置 i = (数组长度 - 1) & hash
    • 4.再次判断并更新临界点

3.put 操作:继续操作:出现突情况时

  • 3.put 操作:继续操作:出现突情况时
    • 当 存放位置 i = (数组长度 - 1) & hash 已经存在数据时
    • 先判断节点类型,链表还是红黑树
    • 是链表,遍历链表
    • 如果当前节点的下一个节点不存在,直接创建插入Node,如果存在判断KEY是否相同,相同就覆盖,不同就继续循环
    • 创建插入Node后,判断长度,是否转为 红黑树
      • binCount >= TREEIFY_THRESHOLD - 1 链表长度大于8 并且
      • (n = tab.length) < MIN_TREEIFY_CAPACITY 并且 数组长度大于64
  • 是红黑树,创建节点插入即可

4.删除:remove

  • 4.删除:remove
    • 1.计算 KEY 的 Hash值, 找到数组中的位置
    • 2.判断KEY是否相同,相同直接删除,不同就判断当前 链表/红黑树 中下一个节点的数据
    • 3.删除:将当前位置指向 next数据,实现从链表中删除数据的功能

5.获取:get

  • 5.获取:get
  • 1.计算 KEY 的 Hash值, 找到数组中的位置
  • 2.判断,数组不为空,并且first不等于空,继续执行,为空直接返回NULL
  • 3.如果first位置的Node是红黑树,getTreeNode() 获取数据
  • 4.如果first位置的Node是链表,遍历链表获取数据

6.补充

  • 默认扩容的临界值初始16
  • 扩容因子(扩容时的倍数),默认0.75f
  • 链表转红黑树(当链表长度大于8时,并且数组长度大于64时, 链表数据结构,转为红黑树)
  • 红黑树转链表的阈值(当链表长度小于6,并且数组长度小于64时, 红黑树数据结构,转为链表)
  • Node节点是一个Map链表结构,特点是 next
  • TreeNode 是一个 LinkedHashMap ,特点是 parent 父节点 left right prev(上一页)

《目录:Java-JDBC学习》

《幕》

  • 留白 —<老吉>
  • ~ 今 ~ ❀ ~ ❀❀❀❀❀❀❀❀❀❀ ❀❀❀❀❀❀❀❀❀❀ ❀❀❀❀❀❀❀
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

面试-Java【之】HashMap原理,源码逐行分析,理论总结(变量、常量、数据结构、Node、TreeNode、初始化、添加、查询、更新、删除) 的相关文章

  • Play框架运行应用程序问题

    每当我尝试运行使用以下命令创建的新 Web 应用程序时 我都会收到以下错误Play http www playframework org Error occurred during initialization of VM Could no
  • Java JDBC:更改表

    我希望对此表进行以下修改 添加 状态列 varchar 20 日期列 时间戳 我不确定该怎么做 String createTable Create table aircraft aircraftNumber int airLineCompa
  • 反射找不到对象子类型

    我试图通过使用反射来获取包中的所有类 当我使用具体类的代码 本例中为 A 时 它可以工作并打印子类信息 B 扩展 A 因此它打印 B 信息 但是当我将它与对象类一起使用时 它不起作用 我该如何修复它 这段代码的工作原理 Reflection
  • JavaMail 只获取新邮件

    我想知道是否有一种方法可以在javamail中只获取新消息 例如 在初始加载时 获取收件箱中的所有消息并存储它们 然后 每当应用程序再次加载时 仅获取新消息 而不是再次重新加载它们 javamail 可以做到这一点吗 它是如何工作的 一些背
  • 路径中 File.separator 和斜杠之间的区别

    使用有什么区别File separator和一个正常的 在 Java 路径字符串中 与双反斜杠相反 平台独立性似乎不是原因 因为两个版本都可以在 Windows 和 Unix 下运行 public class SlashTest Test
  • Spring @RequestMapping 带有可选参数

    我的控制器在请求映射中存在可选参数的问题 请查看下面的控制器 GetMapping produces MediaType APPLICATION JSON VALUE public ResponseEntity
  • Java TestNG 与跨多个测试的数据驱动测试

    我正在电子商务平台中测试一系列商店 每个商店都有一系列属性 我正在考虑对其进行自动化测试 是否有可能有一个数据提供者在整个测试套件中提供数据 而不仅仅是 TestNG 中的测试 我尝试不使用 testNG xml 文件作为机制 因为这些属性
  • 为什么HashMap不能保证map的顺序随着时间的推移保持不变

    我在这里阅读有关 Hashmap 和 Hashtable 之间的区别 http javarevisited blogspot sg 2010 10 difference Between hashmap and html http javar
  • JRE 系统库 [WebSphere v6.1 JRE](未绑定)

    将项目导入 Eclipse 后 我的构建路径中出现以下错误 JRE System Library WebSphere v6 1 JRE unbound 谁知道怎么修它 右键单击项目 特性 gt Java 构建路径 gt 图书馆 gt JRE
  • 如何在控制器、服务和存储库模式中使用 DTO

    我正在遵循控制器 服务和存储库模式 我只是想知道 DTO 在哪里出现 控制器应该只接收 DTO 吗 我的理解是您不希望外界了解底层域模型 从领域模型到 DTO 的转换应该发生在控制器层还是服务层 在今天使用 Spring MVC 和交互式
  • 如何从指定日期获取上周五的日期? [复制]

    这个问题在这里已经有答案了 如何找出上一个 上一个 星期五 或指定日期的任何其他日期的日期 public getDateOnDay Date date String dayName 我不会给出答案 先自己尝试一下 但是 也许这些提示可以帮助
  • 玩!框架:运行“h2-browser”可以运行,但网页不可用

    当我运行命令时activator h2 browser它会使用以下 url 打开浏览器 192 168 1 17 8082 但我得到 使用 Chrome 此网页无法使用 奇怪的是它以前确实有效 从那时起我唯一改变的是JAVA OPTS以启用
  • 获取 JVM 上所有引导类的列表?

    有一种方法叫做findBootstrapClass对于一个类加载器 如果它是引导的 则返回一个类 有没有办法找到类已经加载了 您可以尝试首先通过例如获取引导类加载器呼叫 ClassLoader bootstrapLoader ClassLo
  • 编译器抱怨“缺少返回语句”,即使不可能达到缺少返回语句的条件

    在下面的方法中 编译器抱怨缺少退货声明即使该方法只有一条路径 并且它包含一个return陈述 抑制错误需要另一个return陈述 public int foo if true return 5 鉴于Java编译器可以识别无限循环 https
  • 在 Maven 依赖项中指定 jar 和 test-jar 类型

    我有一个名为 commons 的项目 其中包含运行时和测试的常见内容 在主项目中 我添加了公共资源的依赖项
  • Firebase 添加新节点

    如何将这些节点放入用户节点中 并创建另一个节点来存储帖子 我的数据库参考 databaseReference child user getUid setValue userInformations 您需要使用以下代码 databaseRef
  • 当我从 Netbeans 创建 Derby 数据库时,它存储在哪里?

    当我从 netbeans 创建 Derby 数据库时 它存储在哪里 如何将它与项目的其余部分合并到一个文件夹中 右键单击Databases gt JavaDB in the Service查看并选择Properties This will
  • JGit 检查分支是否已签出

    我正在使用 JGit 开发一个项目 我设法删除了一个分支 但我还想检查该分支是否已签出 我发现了一个变量CheckoutCommand但它是私有的 private boolean isCheckoutIndex return startCo
  • Spring Boot @ConfigurationProperties 不从环境中检索属性

    我正在使用 Spring Boot 1 2 1 并尝试创建一个 ConfigurationProperties带有验证的bean 如下所示 package com sampleapp import java net URL import j
  • 使用 xpath 和 vtd-xml 以字符串形式获取元素的子节点和文本

    这是我的 XML 的一部分

随机推荐

  • JavaScript教程-对象,文本和属性,方括号,计算属性,属性名称限制,in操作符,for..in,对象引用复制,深层克隆const修改

    对象 正如我们在 数据类型 一章学到的 JavaScript 中有八种数据类型 有七种原始类型 因为它们的值只包含一种东西 字符串 数字或者其他 相反 对象则用来存储键值对和更复杂的实体 在 JavaScript 中 对象几乎渗透到了这门编
  • 选择CentOS还是Ubuntu?

    Ubuntu和CentOS都是常见的Linux发行版 它们都有其优点和适用场景 Ubuntu是一种易于使用的操作系统 适合初学者 它具有良好的社区支持和广泛的软件库 因此很容易找到和安装需要的软件 Ubuntu还经常更新软件包 提供新功能和
  • UTXO介绍

    什么是UTXO 在比特币钱包当中 我们通常能够看到账户余额 然而在中本聪设计的比特币系统中 并没有余额这个概念 比特币余额 是由比特币钱包应用派生出来的产物 中本聪发明了UTXO交易模型 并将其应用到比特币当中 UTXO Unspent T
  • 怎样在html中写css样式,hbuilder的css怎么写

    HBuilder怎么查框架的css的属性 HBuilder在用框架时怎么查框架的css的属性 1 js中定义的变量和函数 在引用变量或函数时 可以跳转到定义的位置 包括HTML中同文件内部跳转及HTML向js文件的跳转 2 css中定义的样
  • Java开发工具JDK+IDEA+MySql+maven+tomact+sqlyong+postMan+redis+RMQ+node

    开发工具 JDK 1 8 含1 8中文API 链接 https pan baidu com s 1t43L4nxCqzmCIhKp JZvIg 提取码 9woy 开发工具 IDEA 含解密文档 链接 https pan baidu com
  • Unity普通项目升级为URP通用渲染管线(图文详解)

    Unity普通项目升级为URP通用渲染管线 前言 一 导入Universal RP 二 创建Pipeline Asset 三 设置Graphics 四 更改Rendering 五 素材升级URP 总结 版权声明 前言 我的unity版本是2
  • RASP解决Java安全问题探讨

    Java 语言在应用场景下有更健全的性能 对于很多企业而言是应用程序编写选择中的 Plan A 树大招风 这也使得它成为攻击者重点关注的对象 在软件开发的过程中 程序员通常会引入第三方库提高自己的研发效率 但开源代码的安全性和可靠性很难保证
  • 租用Topaz Video Enhance AI

    智星云算力平台已认证帐号在智星云租赁并使用Topaz Video Enhance AI 1 租用win10渲染镜像 2 设备管理器 查看显卡状态 3 安装 Topaz Video Enhance AI 软件 4 在 preferences
  • ATM(异步传输模式)是什么?

    异步传输模式 ATM 也称为信元中继 在固定大小的信元中传输数据 通过光纤或双绞线电缆 高速交换 在OSI模型的数据链路层 第2层 运行基于ITU T宽带综合业务数字网络 B ISDN 标准的网络技术 该标准是电信业开发的 自动取款机可以同
  • 【区块链论文整理】SIGMOD 篇 (二)

    SIGMOD Special Interest Group On Management Of Data 是数据库三大顶会之一 近几年也发表了不少水平很高的文章 本文主要针对SIGMOD会议中区块链相关的论文进行简单整理 ACM SIGMOD
  • 运算符之 --- 取余运算 %

    取模运算 javascript取模运算是一个表达式的值除以另一个表达式的值 并返回余数 取模在js里就是取余数的意思 a b 是求余数 a b 是求商 Math abs x 是求x的绝对值 12除以5 2 余数是2 即5 2 2 12 所以
  • C++:使用private继承

    在通常的程序设计中很少使用private继承 因为private继承其实相当于 根据某物实现 而这种情况应该通过类成员变量的方式来实现 那么private继承其实只有两个使用场景 1 需要重写虚函数 include
  • MobileSAM:更快的分割一切!面向移动端的轻量级SAM,比FastSAM快4倍!

    点击下方卡片 关注 CVer 公众号 AI CV重磅干货 第一时间送达 点击进入 gt 图像分割和Transformer 交流群 转载自 极市平台 作者 happy 导读 本文提出一种 解耦蒸馏 方案对SAM的ViT H解码器进行蒸馏 同时
  • 从Inception v1,v2,v3,v4,RexNeXt到Xception再到MobileNets,ShuffleNet,MobileNetV2,ShuffleNetV2,MobileNetV3

    v1 Going deeper with convolutions Inception v1的网络 主要提出了Inceptionmodule结构 1 1 3 3 5 5的conv和3 3的pooling组合在一起 最大的亮点就是从NIN N
  • Dart编程语言概览

    Dart编程语言概览 一个简单的Dart程序 注释 单行 多行 数据类型 字面量 输出方式 字符串插值 main 函数 特定的顶级函数 定义变量var 通过这种方式定义变量不需要指定变量类型 定义一个函数 printInteger int
  • 关于RocketMQ的启动时遇到的一些问题及解决方法

    对于RocketMQ的启动需要配置java环境 所以我们需要在linux上下载jdk 并配置JAVA HOME 配置java环境时遇到的文件不能编辑的问题 我们可以看到该文件对于我们来说是只读权限 所以我们需要提升权限用sudo编辑该文件
  • 特征工程系列:GBDT特征构造以及聚类特征构造

    特征工程系列 GBDT特征构造以及聚类特征构造 本文为数据茶水间群友原创 经授权在本公众号发表 关于作者 JunLiang 一个热爱挖掘的数据从业者 勤学好问 动手达人 期待与大家一起交流探讨机器学习相关内容 0x00 前言 数据和特征决定
  • 面试前看过这篇文章就好了

    一 java基础面试 1 1面向对象和面向过程的区别 面向过程 优点 性能比面向对象高 因为类调用时需要实例化 开销比较大 比较消耗 资源 应用场景 单片机 嵌入式开发 Linux Unix 缺点 没有面向对象易维护 易复用 易扩展 面向对
  • JDK8新特性-Function接口与BiFunction接口

    Function 接口 JDK8新增的函数式接口 接口只有一个抽象方法apply 接受一个T类型参数 返回一个R类型参数 T R表示泛型 可以相同 除了一个抽象的apply方法之外 Function存在两个默认的default方法 comp
  • 面试-Java【之】HashMap原理,源码逐行分析,理论总结(变量、常量、数据结构、Node、TreeNode、初始化、添加、查询、更新、删除)

    面试 Java 之 HashMap原理 源码逐行分析 理论总结 变量 常量 数据结构 Node TreeNode 初始化 添加 查询 更新 删除 1 源码分析 1 HashMap属性与变量 扩容因子 扩容阈值 结构转换阈值 2 Node 链