面试-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、初始化、添加、查询、更新、删除) 的相关文章

  • 如何将变量的全部内容发送/导出到文本文件/xml 文件/剪贴板?

    我想将实例的内容 最好以树形形式 发送给某人 打印屏幕是不行的 因为类太复杂了 您需要将输出转回实例吗 在这种情况下 其他答案都是正确的 如果您只想手动检查实例的内容 理想情况下您的类都将实现toString 你可以将其重定向到一个文件 如
  • android.view.InflateException:二进制 XML 文件行 #11:膨胀类 ImageView 时出错

    我只是尝试制作一个小的 android java xml 应用程序来计算游戏的分数 它给了我这个错误 Error inflateing class ImageView 有人知道解决方案吗 我实际上搜索了 ppl 说添加这个 android
  • 如何将 JSpinner 的值设置为特定日期

    我有一个JSpinner我添加到JPanel我想将其时间设置为 GregorianCalendar calendar JSpinner spinner new JSpinner spinner setModel model pom add
  • 将一种类型的对象声明为另一种类型的实例有什么好处? [复制]

    这个问题在这里已经有答案了 可能的重复 Base b2 new Child 是什么意思 表示 https stackoverflow com questions 4447924 what does base b2 new child sig
  • Quarkus 不以编程方式选择 bean

    我试图以编程方式选择 bean 但 quarkus 不会注入 bean 并引发异常 不支持吗 public enum ReportType ONE TWO Qualifier Retention RUNTIME Target METHOD
  • 如何配置 Spring-WS 以使用 JAXB Marshaller?

    感谢您到目前为止对此的帮助 我正在更新问题 因为我没有显示我需要的所有内容 并显示了建议的更改 肥皂输出仍然不是我想要的 servlet xml
  • JavaFX 2.0 FXML 子窗口

    经过多次搜索我发现了这个问题如何创建 javafx 2 0 应用程序 MDI https stackoverflow com questions 10915388 how to create a javafx 2 0 application
  • 迁移到Java 9或更高版本时是否需要切换到模块?

    我们目前正在从 Java 8 迁移到 Java 11 但是 升级我们的服务并没有我们预期的那么痛苦 我们基本上只需要更改我们的版本号build gradle文件和服务都顺利启动并运行 我们升级了库以及使用这些库的 微 服务 到目前为止没有问
  • 如何将现有的 SQLite3 数据库导入 Room?

    好吧 我在桌面上使用 SQLite3 创建了一个只需要读取的某些信息的数据库 我正在制作的应用程序不需要在此表中插入或删除信息 我在 Room 数据库层上做了相当多的谷歌搜索 所有文档都需要在构建应用程序时在 Room 中创建一个新的数据库
  • java中的单链表和双向链表?

    在java中 哪个集合接口可以有效地实现单链表和双向链表 请问代码示例吗 毫不奇怪 实现双向链表的正确接口是 LinkedList 看Java文档 http docs oracle com javase 8 docs api java ut
  • Android WebView文件上传

    我正在开发一个 Android 应用程序 基本上它是一个WebView和一个进度条 Facebook 的移动网站 m facebook com 已加载到WebView 当我单击 选择文件 按钮上传图像时 没有任何反应 我已经尝试了所有的解决
  • Android volley使用RequestFuture.get()时出现超时异常

    在我的片段中 我尝试使用 TMDB 的开放电影数据库来获取有关 正在播放 电影的详细信息 如果我使用 RequestFuture get time TimeUnit 方法来执行此齐射请求 我总是会收到超时错误 如果我在 Safari 中手动
  • Java 中的 ExecuteUpdate sql 语句不起作用

    我正在学习如何将 SQL 与 Java 结合使用 我已成功安装 JDBC 驱动程序 并且能够从数据库读取记录并将其打印在屏幕上 我的问题发生在尝试执行更新或插入语句时 没有任何反应 这是我的代码 问题所在的方法 public static
  • 查找数组中的组合

    我在java中有一个像这样的二维数组 transmission communication tv television approach memorycode methodact 我需要获得所有组合 例如 transmission appr
  • 是否有最新的 Facebook Java SDK? [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 好像没找到最近更新的 如果没有 是否有一个好的 Java 库来执行与 Facebook 的 API 交
  • java swing:向 JTree 项目添加自定义图形按钮

    我想在 JTree 中的项目右侧添加一个带有小图标的附加按钮 这可以做到吗 如果是这样 怎么办 thanks Clamp 你在这方面成功了吗 我想做同样的事情 但很难让 JButton 响应用户 设置渲染器以显示按钮的过程很顺利 但所有鼠标
  • 如何检查日期字符串的有效性?

    在我的项目中 我需要检查日期字符串是否计算为正确的日期对象 我决定允许 yyyy MM dd 和日期格式 年 月 日 和 年 月 日 小时 分钟 我如何检查它们是否有效 我的代码为 1980 01 01 和一些奇怪的日期 如 3837 05
  • 传递 Android DialogFragment 参数时,onCreateDialog 捆绑参数意外为 null

    我正在尝试使用 DialogFragment 在 Android 中显示一个基本对话框 并使用对话框消息的参数 如中所述StackOverflow线程 https stackoverflow com questions 15459209 p
  • java中的预增量/后增量

    有人可以帮助我理解为什么 int i 1 int j 1 int k 1 int l 1 System out println i i System out println j j System out println k k System
  • 使用自定义比较器在 Java 中创建 SortedMap

    我想创建一个TreeMap在 Java 中具有自定义排序顺序 排序后的键是字符串 需要根据第二个字符进行排序 这些值也是字符串 示例地图 Za FOO Ab Bar 您可以像这样使用自定义比较器 Comparator

随机推荐

  • 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 链