当前位置: 首页 > news >正文

知乎的网站建设和网站运营如何自己建立网站建设

知乎的网站建设和网站运营,如何自己建立网站建设,仓山区seo引擎优化软件,网站后端建设总有人心里有火炬#xff0c;而且彼此能看见。高手过招#xff0c;招招致命JDK1.8 中 HashMap 的底层实现#xff0c;我相信大家都能说上来个 一二#xff0c;底层数据结构 数组 链表(或红黑树) #xff0c;源码如下/*** 数组*/transient Node[] table;/*** 链表结构*/st…总有人心里有火炬而且彼此能看见。高手过招招招致命JDK1.8 中 HashMap 的底层实现我相信大家都能说上来个 一二底层数据结构 数组 链表(或红黑树) 源码如下/*** 数组*/transient Node[] table;/*** 链表结构*/static class Node implements Map.Entry {final int hash;final K key;V value;Node next;Node(int hash, K key, V value, Node 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; }public final int hashCode() {return Objects.hashCode(key) ^ Objects.hashCode(value);}public final V setValue(V newValue) {V oldValue value;value newValue;return oldValue;}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;}}/*** 红黑树结构*/static final class TreeNode extends LinkedHashMap.Entry {TreeNode parent; // red-black tree linksTreeNode left;TreeNode right;TreeNode prev; // needed to unlink next upon deletionboolean red;...但面试往往会问的比较细例如下面的容量问题我们能答上来几个1、table 的初始化时机是什么时候初始化的 table.length 是多少、阀值(threshold)是多少实际能容下多少元素2、什么时候触发扩容扩容之后的 table.length、阀值各是多少3、table 的 length 为什么是 2 的 n 次幂4、求索引的时候为什么是h(length-1)而不是 hlength更不是 h%length5、 Map map new HashMap(1000); 当我们存入多少个元素时会触发map的扩容Map map1 new HashMap(10000); 我们存入第 10001个元素时会触发 map1 扩容吗6、为什么加载因子的默认值是 0.75并且不推荐我们修改由于我们平时关注的少一旦碰上这样的 连击 暴击我们往往不知所措、无从应对接下来我们看看上面的 6 个问题是不是真的难到无法理解 还是我们不够细心、在自信的自我认为斗智斗勇见招拆招上述的问题我们如何去找答案 ? 方式有很多种用的最多的我想应该是上网查资料、看别人的博客但我认为最有效、准确的方式是读源码问题 1table 的初始化HashMap 的构造方法有如下 4 种/*** 构造方法 1** 通过 指定的 initialCapacity 和 loadFactor 实例化一个空的 HashMap 对象*/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);}/*** 构造方法 2** 通过指定的 initialCapacity 和 默认的 loadFactor(0.75) 实例化一个空的 HashMap 对象*/public HashMap(int initialCapacity) {this(initialCapacity, DEFAULT_LOAD_FACTOR);}/*** 构造方法 3** 通过默认的 initialCapacity 和 默认的 loadFactor(0.75) 实例化一个空的 HashMap 对象*/public HashMap() {this.loadFactor DEFAULT_LOAD_FACTOR; // all other fields defaulted}/**** 构造方法 4* 通过指定的 Map 对象实例化一个 HashMap 对象*/public HashMap(Map extends K, ? extends V m) {this.loadFactor DEFAULT_LOAD_FACTOR;putMapEntries(m, false);}构造方式 4 和 构造方式 1 实际应用的不多构造方式 2 直接调用的 1(底层实现完全一致)构造方式 2 和 构造方式 3 比较常用而最常用的是构造方式 3此时我们以构造方式 3 为前提来分析而构造方式 2 我们则在问题 5 中来分析使用方式 1 实例化 HashMap 的时候table 并未进行初始化那 table 是何时进行初始化的了 平时我们是如何使用 HashMap 的先实例化、然后 put、然后进行其他操作如下Map map new HashMap();map.put(name, 张三);map.put(age, 21);// 后续操作...既然实例化的时候未进行 table 的初始化那是不是在 put 的时候初始化的了我们来确认下:resize() 初始化 table 或 对 table 进行双倍扩容源码如下(注意看注释)/*** Initializes or doubles table size. If null, allocates in* accord with initial capacity target held in field threshold.* Otherwise, because we are using power-of-two expansion, the* elements from each bin must either stay at same index, or move* with a power of two offset in the new table.** return the table*/final Node[] resize() {Node[] oldTab table; // 第一次 put 的时候table nullint oldCap (oldTab null) ? 0 : oldTab.length; // oldCap 0int oldThr threshold; // threshold0, oldThr 0int newCap, newThr 0;if (oldCap 0) { // 条件不满足往下走if (oldCap MAXIMUM_CAPACITY) {threshold Integer.MAX_VALUE;return oldTab;}else if ((newCap oldCap 1) MAXIMUM_CAPACITY oldCap DEFAULT_INITIAL_CAPACITY)newThr oldThr 1; // double threshold}else if (oldThr 0) // initial capacity was placed in thresholdnewCap oldThr;else { // zero initial threshold signifies using defaults 走到这里进行默认初始化newCap DEFAULT_INITIAL_CAPACITY; // DEFAULT_INITIAL_CAPACITY 1 4 16, newCap 16;newThr (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY); // newThr 0.75 * 16 12;}if (newThr 0) { // 条件不满足float ft (float)newCap * loadFactor;newThr (newCap MAXIMUM_CAPACITY ft (float)MAXIMUM_CAPACITY ?(int)ft : Integer.MAX_VALUE);}threshold newThr; // threshold 12; 重置阀值为12SuppressWarnings({rawtypes,unchecked})Node[] newTab (Node[])new Node[newCap]; // 初始化 newTab, length 16;table newTab; // table 初始化完成, length 16;if (oldTab ! null) { // 此时条件不满足后续扩容的时候走此if分支 将数组元素复制到新数组for (int j 0; j oldCap; j) {Node e;if ((e oldTab[j]) ! null) {oldTab[j] null;if (e.next null)newTab[e.hash (newCap - 1)] e;else if (e instanceof TreeNode)((TreeNode)e).split(this, newTab, j, oldCap);else { // preserve orderNode loHead null, loTail null;Node hiHead null, hiTail null;Node next;do {next e.next;if ((e.hash oldCap) 0) {if (loTail null)loHead e;elseloTail.next e;loTail e;}else {if (hiTail null)hiHead e;elsehiTail.next e;hiTail e;}} while ((e next) ! null);if (loTail ! null) {loTail.next null;newTab[j] loHead;}if (hiTail ! null) {hiTail.next null;newTab[j oldCap] hiHead;}}}}}return newTab; // 新数组}自此问题 1 的答案就明了了table 的初始化时机是什么时候一般情况下在第一次 put 的时候调用 resize 方法进行 table 的初始化(懒初始化懒加载思想在很多框架中都有应用)初始化的 table.length 是多少、阀值(threshold)是多少实际能容下多少元素默认情况下table.length 16; 指定了 initialCapacity 的情况放到问题 5 中分析默认情况下threshold 12; 指定了 initialCapacity 的情况放到问题 5 中分析默认情况下能存放 12 个元素当存放第 13 个元素后进行扩容问题 2 table 的扩容putVal 源码如下/*** Implements Map.put and related methods** param hash hash for key* param key the key* param value the value to put* param onlyIfAbsent if true, dont change existing value* param evict if false, the table is in creation mode.* return previous value, or null if none*/final V putVal(int hash, K key, V value, boolean onlyIfAbsent,boolean evict) {Node[] tab; Node 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 e; K k;if (p.hash hash ((k p.key) key || (key ! null key.equals(k))))e p;else if (p instanceof TreeNode)e ((TreeNode)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 1sttreeifyBin(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 keyV oldValue e.value;if (!onlyIfAbsent || oldValue null)e.value value;afterNodeAccess(e);return oldValue;}}modCount;if (size threshold) // 当size(已存放元素个数) thrshold(阀值)进行扩容resize();afterNodeInsertion(evict);return null;}还是调用 resize() 进行扩容但与初始化时不同(注意看注释)/*** Initializes or doubles table size. If null, allocates in* accord with initial capacity target held in field threshold.* Otherwise, because we are using power-of-two expansion, the* elements from each bin must either stay at same index, or move* with a power of two offset in the new table.** return the table*/final Node[] resize() {Node[] oldTab table; // 此时的 table ! nulloldTab 指向旧的 tableint oldCap (oldTab null) ? 0 : oldTab.length; // oldCap table.length; 第一次扩容时是 16int oldThr threshold; // threshold12, oldThr 12;int newCap, newThr 0;if (oldCap 0) { // 条件满足走此分支if (oldCap MAXIMUM_CAPACITY) {threshold Integer.MAX_VALUE;return oldTab;}else if ((newCap oldCap 1) MAXIMUM_CAPACITY // oldCap左移一位; newCap 16 1 32;oldCap DEFAULT_INITIAL_CAPACITY)newThr oldThr 1; // double threshold // newThr 12 1 24;}else if (oldThr 0) // initial capacity was placed in thresholdnewCap oldThr;else { // zero initial threshold signifies using defaultsnewCap DEFAULT_INITIAL_CAPACITY; // DEFAULT_INITIAL_CAPACITY 1 4 16, newCap 16;newThr (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);}if (newThr 0) { // 条件不满足float ft (float)newCap * loadFactor;newThr (newCap MAXIMUM_CAPACITY ft (float)MAXIMUM_CAPACITY ?(int)ft : Integer.MAX_VALUE);}threshold newThr; // threshold newThr 24; 重置阀值为 24SuppressWarnings({rawtypes,unchecked})Node[] newTab (Node[])new Node[newCap]; // 初始化 newTab, length 32;table newTab; // table 指向 newTab, length 32;if (oldTab ! null) { // 扩容后将 oldTab(旧table) 中的元素移到 newTab(新table)中for (int j 0; j oldCap; j) {Node e;if ((e oldTab[j]) ! null) {oldTab[j] null;if (e.next null)newTab[e.hash (newCap - 1)] e; //else if (e instanceof TreeNode)((TreeNode)e).split(this, newTab, j, oldCap);else { // preserve orderNode loHead null, loTail null;Node hiHead null, hiTail null;Node next;do {next e.next;if ((e.hash oldCap) 0) {if (loTail null)loHead e;elseloTail.next e;loTail e;}else {if (hiTail null)hiHead e;elsehiTail.next e;hiTail e;}} while ((e next) ! null);if (loTail ! null) {loTail.next null;newTab[j] loHead;}if (hiTail ! null) {hiTail.next null;newTab[j oldCap] hiHead;}}}}}return newTab;}自此问题 2 的答案也就清晰了什么时候触发扩容扩容之后的 table.length、阀值各是多少当 size threshold 的时候进行扩容扩容之后的 table.length 旧 table.length * 2,扩容之后的 threshold 旧 threshold * 2问题 3、4 2 的 n 次幂table 是一个数组那么如何最快的将元素 e 放入数组 当然是找到元素 e 在 table 中对应的位置 index 然后 table[index] e; 就好了如何找到 e 在 table 中的位置了 我们知道只能通过数组下标(索引)操作数组而数组的下标类型又是 int 如果 e 是 int 类型那好说就直接用 e 来做数组下标(若 e table.length则可以 e % table.length 来获取下标)可 key - value 中的 key 类型不一定所以我们需要一种统一的方式将 key 转换成 int 最好是一个 key 对应一个唯一的 int (目前还不可能, int有范围限制对转换方法要求也极高)所以引入了 hash 方法static final int hash(Object key) {int h;return (key null) ? 0 : (h key.hashCode()) ^ (h 16);  // 这里的处理有兴趣的可以琢磨下能够减少碰撞}实现 key 到 int 的转换(关于 hash本文不展开讨论)。拿到了 key 对应的 int h 之后我们最容易想到的对 value 的 put 和 get 操作也许如下// puttable[h % table.length] value;// gete table[h % table.length];直接取模是我们最容易想到的获取下标的方法但是最高效的方法吗 我们知道计算机中的四则运算最终都会转换成二进制的位运算我们可以发现只有 数是1时 运算的结果与被 数一致111;010;100;000;这同样适用于多位操作数101011111010; 101510;101111111011; 111511;010101000000000; 10160;010111000000000; 11160;我们是不是又有所发现10 16 与 11 16 得到的结果一样也就是冲突(碰撞)了那么 10 和 11 对应的 value 会在同一个链表中而 table 的有些位置则永远不会有元素这就导致 table 的空间未得到充分利用同时还降低了 put 和 get 的效率(对比数组和链表)由于是 2 个数进行 运算所以结果由这两个数决定如果我们把这两个数都做下限制那得到的结果是不是可控制在我们想要的范围内了 我们需要利用好 运算的特点当右边的数的低位二进制是连续的 1 且左边是一个均匀的数(需要 hash 方法实现尽量保证 key 的 h 唯一)那么得到的结果就比较完美了。低位二进制连续的 1我们很容易想到 2^n - 1; 而关于左边均匀的数则通过 hash 方法来实现这里不做细究了。更多面试题欢迎关注 公众号Java面试题精选自此2 的 n 次幂的相关问题就清楚了table 的 length 为什么是 2 的 n 次幂为了利用位运算 求 key 的下标求索引的时候为什么是h(length-1)而不是 hlength更不是 h%lengthh%length 效率不如位运算快hlength 会提高碰撞几率导致 table 的空间得不到更充分的利用、降低 table 的操作效率给各位留个疑问为什么不直接用 2^n-1 作为 table.length 欢迎评论区留言问题 5指定 initialCapacity当我们指定了 initialCapacityHashMap的构造方法有些许不同调用 tableSizeFor 进行 threshold 的初始化/*** Returns a power of two size for the given target capacity.* 返回 cap 最小的 2^n* cap 10, 则返回 2^4 16;* cap 5, 则返回 2^3 8;*/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;}虽然此处初始化的是 threshold但后面初始化 table 的时候会将其用于 table 的 length同时会重置 threshold 为 table.length * loadFactor自此问题 5 也就清楚了Map map new HashMap(1000); 当我们存入多少个元素时会触发map的扩容此时的 table.length 2^10 1024; threshold 1024 * 0.75 768; 所以存入第 769 个元素时进行扩容Map map1 new HashMap(10000); 我们存入第 10001个元素时会触发 map1 扩容吗此时的 table.length 2^14 16384; threshold 16384 * 0.75 12288; 所以存入第 10001 个元素时不会进行扩容问题6加载因子为什么加载因子的默认值是 0.75并且不推荐我们修改如果loadFactor太小那么map中的table需要不断的扩容扩容是个耗时的过程如果loadFactor太大那么map中table放满了也不不会扩容导致冲突越来越多解决冲突而起的链表越来越长效率越来越低而 0.75 这是一个折中的值是一个比较理想的值总结1、table.length 2^n是为了能利用位运算()来求 key 的下标而 h(length-1) 是为了充分利用 table 的空间并减少 key 的碰撞2、加载因子太小 table 需要不断的扩容影响 put 效率太大会导致碰撞越来越多链表越来越长(转红黑树)影响效率0.75 是一个比较理想的中间值3、table.length 2^n、hash 方法获取 key 的 h、加载因子 0.75、数组 链表(或红黑树)一环扣一环保证了 key 在 table 中的均匀分配充分利用了空间也保证了操作效率环环相扣的而不是心血来潮的随意处理缺了一环其他的环就无意义了4、网上有个 put 方法的流程图画的挺好我就偷懒了
http://www.yutouwan.com/news/140915/

相关文章:

  • 万全孔家庄做网站如何维护企业电子商务网站建设
  • wordpress搬站skr搜索引擎入口
  • 在线图片编辑网站源码怎么用php自己做网站
  • 中国十大做网站公司排名新媒体运营培训班
  • 婚庆网站建设外国风格网站建设费用
  • 怎么建设一个购买卡密的网站亳州市网站建设公司
  • 乐之网站制作网页微信登陆首页
  • 动感十足的网站怎么开通公司网站
  • 邢台哪里建网站凡客资源
  • 网站做标准曲线怎么自己注册域名
  • 科技 杭州 网站建设烟台网站建设ytwzjs
  • 做损坏文档的网站无法打开网页是怎么回事
  • html网站设计模板下载ui设计包括哪些
  • 在建项目人员查询网站wordpress的官方网站
  • 自己制作网站做外贸赚钱吗策划案推广
  • 自动写作文网站如何查看网站开发单位
  • 做网站涉及到哪些广州关键词快速排名
  • 制作网站数据库外贸累网站
  • 网站后台用什么语言网站备案包括空间内容吗
  • 外贸网站商城短剧小程序代理
  • 烟台提供网站设计制作wordpress登录卡死
  • 滨海做网站的公司找个网站怎么那么难
  • 博客做网站网站建设要用什么软件
  • 网站开发常用png私密浏览器免费版在线看小说
  • ps做网站首页效果特效python 有wordpress
  • 太原企业建站模板公司在选择网站时应考虑什么
  • 网站建设 工具seo优化一般包括
  • 如何进行网站关键词优化域名还没备案可以做网站吗
  • 东莞网站建设规范河南省招生网站服务平台
  • 万维网注册域名后怎么导入网站用dw做网页的步骤