<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>tonngw&#39;s Blog</title>
  
  <subtitle>开博客就要写吖！</subtitle>
  <link href="https://tonngw.com/atom.xml" rel="self"/>
  
  <link href="https://tonngw.com/"/>
  <updated>2022-07-26T13:44:58.235Z</updated>
  <id>https://tonngw.com/</id>
  
  <author>
    <name>tonngw</name>
    
  </author>
  
  <generator uri="https://hexo.io/">Hexo</generator>
  
  <entry>
    <title>HashMap 源码精读笔记</title>
    <link href="https://tonngw.com/2022/07/26/HashMap%20%E6%BA%90%E7%A0%81%E7%B2%BE%E8%AF%BB/"/>
    <id>https://tonngw.com/2022/07/26/HashMap%20%E6%BA%90%E7%A0%81%E7%B2%BE%E8%AF%BB/</id>
    <published>2022-07-26T13:11:03.888Z</published>
    <updated>2022-07-26T13:44:58.235Z</updated>
    
    <content type="html"><![CDATA[<h2 id="HashMap-类属性"><a href="#HashMap-类属性" class="headerlink" title="HashMap 类属性"></a>HashMap 类属性</h2><p>HashMap 继承于 AbstractMap，实现了 Map、Cloneable、java.io.Serializable 接口，是非常常用的一个集合类，同时在 JDK 1.7 和 JDK 1.8 版本的底层实现上也有很大区别。</p><span id="more"></span><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br><span class="line">266</span><br><span class="line">267</span><br><span class="line">268</span><br><span class="line">269</span><br><span class="line">270</span><br><span class="line">271</span><br><span class="line">272</span><br><span class="line">273</span><br><span class="line">274</span><br><span class="line">275</span><br><span class="line">276</span><br><span class="line">277</span><br><span class="line">278</span><br><span class="line">279</span><br><span class="line">280</span><br><span class="line">281</span><br><span class="line">282</span><br><span class="line">283</span><br><span class="line">284</span><br><span class="line">285</span><br><span class="line">286</span><br><span class="line">287</span><br><span class="line">288</span><br><span class="line">289</span><br><span class="line">290</span><br><span class="line">291</span><br><span class="line">292</span><br><span class="line">293</span><br><span class="line">294</span><br><span class="line">295</span><br><span class="line">296</span><br><span class="line">297</span><br><span class="line">298</span><br><span class="line">299</span><br><span class="line">300</span><br><span class="line">301</span><br><span class="line">302</span><br><span class="line">303</span><br><span class="line">304</span><br><span class="line">305</span><br><span class="line">306</span><br><span class="line">307</span><br><span class="line">308</span><br><span class="line">309</span><br><span class="line">310</span><br><span class="line">311</span><br><span class="line">312</span><br><span class="line">313</span><br><span class="line">314</span><br><span class="line">315</span><br><span class="line">316</span><br><span class="line">317</span><br><span class="line">318</span><br><span class="line">319</span><br><span class="line">320</span><br><span class="line">321</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> java.util;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.IOException;</span><br><span class="line"><span class="keyword">import</span> java.io.InvalidObjectException;</span><br><span class="line"><span class="keyword">import</span> java.io.Serializable;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.ParameterizedType;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.Type;</span><br><span class="line"><span class="keyword">import</span> java.util.function.BiConsumer;</span><br><span class="line"><span class="keyword">import</span> java.util.function.BiFunction;</span><br><span class="line"><span class="keyword">import</span> java.util.function.Consumer;</span><br><span class="line"><span class="keyword">import</span> java.util.function.Function;</span><br><span class="line"><span class="keyword">import</span> sun.misc.SharedSecrets;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Hash table based implementation of the &lt;tt&gt;Map&lt;/tt&gt; interface.  This</span></span><br><span class="line"><span class="comment"> * implementation provides all of the optional map operations, and permits</span></span><br><span class="line"><span class="comment"> * &lt;tt&gt;null&lt;/tt&gt; values and the &lt;tt&gt;null&lt;/tt&gt; key.  (The &lt;tt&gt;HashMap&lt;/tt&gt;</span></span><br><span class="line"><span class="comment"> * class is roughly equivalent to &lt;tt&gt;Hashtable&lt;/tt&gt;, except that it is</span></span><br><span class="line"><span class="comment"> * unsynchronized and permits nulls.)  This class makes no guarantees as to</span></span><br><span class="line"><span class="comment"> * the order of the map; in particular, it does not guarantee that the order</span></span><br><span class="line"><span class="comment"> * will remain constant over time.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * &lt;p&gt;This implementation provides constant-time performance for the basic</span></span><br><span class="line"><span class="comment"> * operations (&lt;tt&gt;get&lt;/tt&gt; and &lt;tt&gt;put&lt;/tt&gt;), assuming the hash function</span></span><br><span class="line"><span class="comment"> * disperses the elements properly among the buckets.  Iteration over</span></span><br><span class="line"><span class="comment"> * collection views requires time proportional to the &quot;capacity&quot; of the</span></span><br><span class="line"><span class="comment"> * &lt;tt&gt;HashMap&lt;/tt&gt; instance (the number of buckets) plus its size (the number</span></span><br><span class="line"><span class="comment"> * of key-value mappings).  Thus, it&#x27;s very important not to set the initial</span></span><br><span class="line"><span class="comment"> * capacity too high (or the load factor too low) if iteration performance is</span></span><br><span class="line"><span class="comment"> * important.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * &lt;p&gt;An instance of &lt;tt&gt;HashMap&lt;/tt&gt; has two parameters that affect its</span></span><br><span class="line"><span class="comment"> * performance: &lt;i&gt;initial capacity&lt;/i&gt; and &lt;i&gt;load factor&lt;/i&gt;.  The</span></span><br><span class="line"><span class="comment"> * &lt;i&gt;capacity&lt;/i&gt; is the number of buckets in the hash table, and the initial</span></span><br><span class="line"><span class="comment"> * capacity is simply the capacity at the time the hash table is created.  The</span></span><br><span class="line"><span class="comment"> * &lt;i&gt;load factor&lt;/i&gt; is a measure of how full the hash table is allowed to</span></span><br><span class="line"><span class="comment"> * get before its capacity is automatically increased.  When the number of</span></span><br><span class="line"><span class="comment"> * entries in the hash table exceeds the product of the load factor and the</span></span><br><span class="line"><span class="comment"> * current capacity, the hash table is &lt;i&gt;rehashed&lt;/i&gt; (that is, internal data</span></span><br><span class="line"><span class="comment"> * structures are rebuilt) so that the hash table has approximately twice the</span></span><br><span class="line"><span class="comment"> * number of buckets.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * &lt;p&gt;As a general rule, the default load factor (.75) offers a good</span></span><br><span class="line"><span class="comment"> * tradeoff between time and space costs.  Higher values decrease the</span></span><br><span class="line"><span class="comment"> * space overhead but increase the lookup cost (reflected in most of</span></span><br><span class="line"><span class="comment"> * the operations of the &lt;tt&gt;HashMap&lt;/tt&gt; class, including</span></span><br><span class="line"><span class="comment"> * &lt;tt&gt;get&lt;/tt&gt; and &lt;tt&gt;put&lt;/tt&gt;).  The expected number of entries in</span></span><br><span class="line"><span class="comment"> * the map and its load factor should be taken into account when</span></span><br><span class="line"><span class="comment"> * setting its initial capacity, so as to minimize the number of</span></span><br><span class="line"><span class="comment"> * rehash operations.  If the initial capacity is greater than the</span></span><br><span class="line"><span class="comment"> * maximum number of entries divided by the load factor, no rehash</span></span><br><span class="line"><span class="comment"> * operations will ever occur.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * &lt;p&gt;If many mappings are to be stored in a &lt;tt&gt;HashMap&lt;/tt&gt;</span></span><br><span class="line"><span class="comment"> * instance, creating it with a sufficiently large capacity will allow</span></span><br><span class="line"><span class="comment"> * the mappings to be stored more efficiently than letting it perform</span></span><br><span class="line"><span class="comment"> * automatic rehashing as needed to grow the table.  Note that using</span></span><br><span class="line"><span class="comment"> * many keys with the same &#123;<span class="doctag">@code</span> hashCode()&#125; is a sure way to slow</span></span><br><span class="line"><span class="comment"> * down performance of any hash table. To ameliorate impact, when keys</span></span><br><span class="line"><span class="comment"> * are &#123;<span class="doctag">@link</span> Comparable&#125;, this class may use comparison order among</span></span><br><span class="line"><span class="comment"> * keys to help break ties.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * &lt;p&gt;&lt;strong&gt;Note that this implementation is not synchronized.&lt;/strong&gt;</span></span><br><span class="line"><span class="comment"> * If multiple threads access a hash map concurrently, and at least one of</span></span><br><span class="line"><span class="comment"> * the threads modifies the map structurally, it &lt;i&gt;must&lt;/i&gt; be</span></span><br><span class="line"><span class="comment"> * synchronized externally.  (A structural modification is any operation</span></span><br><span class="line"><span class="comment"> * that adds or deletes one or more mappings; merely changing the value</span></span><br><span class="line"><span class="comment"> * associated with a key that an instance already contains is not a</span></span><br><span class="line"><span class="comment"> * structural modification.)  This is typically accomplished by</span></span><br><span class="line"><span class="comment"> * synchronizing on some object that naturally encapsulates the map.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * If no such object exists, the map should be &quot;wrapped&quot; using the</span></span><br><span class="line"><span class="comment"> * &#123;<span class="doctag">@link</span> Collections#synchronizedMap Collections.synchronizedMap&#125;</span></span><br><span class="line"><span class="comment"> * method.  This is best done at creation time, to prevent accidental</span></span><br><span class="line"><span class="comment"> * unsynchronized access to the map:&lt;pre&gt;</span></span><br><span class="line"><span class="comment"> *   Map m = Collections.synchronizedMap(new HashMap(...));&lt;/pre&gt;</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * &lt;p&gt;The iterators returned by all of this class&#x27;s &quot;collection view methods&quot;</span></span><br><span class="line"><span class="comment"> * are &lt;i&gt;fail-fast&lt;/i&gt;: if the map is structurally modified at any time after</span></span><br><span class="line"><span class="comment"> * the iterator is created, in any way except through the iterator&#x27;s own</span></span><br><span class="line"><span class="comment"> * &lt;tt&gt;remove&lt;/tt&gt; method, the iterator will throw a</span></span><br><span class="line"><span class="comment"> * &#123;<span class="doctag">@link</span> ConcurrentModificationException&#125;.  Thus, in the face of concurrent</span></span><br><span class="line"><span class="comment"> * modification, the iterator fails quickly and cleanly, rather than risking</span></span><br><span class="line"><span class="comment"> * arbitrary, non-deterministic behavior at an undetermined time in the</span></span><br><span class="line"><span class="comment"> * future.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * &lt;p&gt;Note that the fail-fast behavior of an iterator cannot be guaranteed</span></span><br><span class="line"><span class="comment"> * as it is, generally speaking, impossible to make any hard guarantees in the</span></span><br><span class="line"><span class="comment"> * presence of unsynchronized concurrent modification.  Fail-fast iterators</span></span><br><span class="line"><span class="comment"> * throw &lt;tt&gt;ConcurrentModificationException&lt;/tt&gt; on a best-effort basis.</span></span><br><span class="line"><span class="comment"> * Therefore, it would be wrong to write a program that depended on this</span></span><br><span class="line"><span class="comment"> * exception for its correctness: &lt;i&gt;the fail-fast behavior of iterators</span></span><br><span class="line"><span class="comment"> * should be used only to detect bugs.&lt;/i&gt;</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * &lt;p&gt;This class is a member of the</span></span><br><span class="line"><span class="comment"> * &lt;a href=&quot;&#123;<span class="doctag">@docRoot</span>&#125;/../technotes/guides/collections/index.html&quot;&gt;</span></span><br><span class="line"><span class="comment"> * Java Collections Framework&lt;/a&gt;.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> &lt;K&gt; the type of keys maintained by this map</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> &lt;V&gt; the type of mapped values</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span>  Doug Lea</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span>  Josh Bloch</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span>  Arthur van Hoff</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span>  Neal Gafter</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@see</span>     Object#hashCode()</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@see</span>     Collection</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@see</span>     Map</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@see</span>     TreeMap</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@see</span>     Hashtable</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@since</span>   1.2</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="comment">// 这里继承了 AbstractMap&lt;K,V&gt;，而 AbstractMap&lt;K,V&gt; 也实现了 Map 接口，所以这里每没必要再去实现 Map 接口，会产生什么影响呢？</span></span><br><span class="line"><span class="comment">// 1. 在 java 文件编译成 class 字节码文件时</span></span><br><span class="line"><span class="comment">// 首先会把 java.util.Map 会被编译到 CONSTANT_UTF8_INFO 中，最终完全字面量的解析</span></span><br><span class="line"><span class="comment">//如果多实现一个接口的情况下，在接口索引集合中会多出一个接口</span></span><br><span class="line"><span class="comment">// 2. class 文件最终会被加载到运行时数据区的方法区形成一个动态数据结构，每次调用 HashMap 时这个 Map 接口都会加载</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">HashMap</span>&lt;K,V&gt; <span class="keyword">extends</span> <span class="title class_">AbstractMap</span>&lt;K,V&gt;</span><br><span class="line">    <span class="keyword">implements</span> <span class="title class_">Map</span>&lt;K,V&gt;, Cloneable, Serializable &#123; <span class="comment">// 实现了 Map、Cloneable、Serializable</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">long</span> <span class="variable">serialVersionUID</span> <span class="operator">=</span> <span class="number">362498820763181265L</span>; <span class="comment">// 随机序列化编号</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">/*</span></span><br><span class="line"><span class="comment">     * Implementation notes.</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * This map usually acts as a binned (bucketed) hash table, but</span></span><br><span class="line"><span class="comment">     * when bins get too large, they are transformed into bins of</span></span><br><span class="line"><span class="comment">     * TreeNodes, each structured similarly to those in</span></span><br><span class="line"><span class="comment">     * java.util.TreeMap. Most methods try to use normal bins, but</span></span><br><span class="line"><span class="comment">     * relay to TreeNode methods when applicable (simply by checking</span></span><br><span class="line"><span class="comment">     * instanceof a node).  Bins of TreeNodes may be traversed and</span></span><br><span class="line"><span class="comment">     * used like any others, but additionally support faster lookup</span></span><br><span class="line"><span class="comment">     * when overpopulated. However, since the vast majority of bins in</span></span><br><span class="line"><span class="comment">     * normal use are not overpopulated, checking for existence of</span></span><br><span class="line"><span class="comment">     * tree bins may be delayed in the course of table methods.</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * Tree bins (i.e., bins whose elements are all TreeNodes) are</span></span><br><span class="line"><span class="comment">     * ordered primarily by hashCode, but in the case of ties, if two</span></span><br><span class="line"><span class="comment">     * elements are of the same &quot;class C implements Comparable&lt;C&gt;&quot;,</span></span><br><span class="line"><span class="comment">     * type then their compareTo method is used for ordering. (We</span></span><br><span class="line"><span class="comment">     * conservatively check generic types via reflection to validate</span></span><br><span class="line"><span class="comment">     * this -- see method comparableClassFor).  The added complexity</span></span><br><span class="line"><span class="comment">     * of tree bins is worthwhile in providing worst-case O(log n)</span></span><br><span class="line"><span class="comment">     * operations when keys either have distinct hashes or are</span></span><br><span class="line"><span class="comment">     * orderable, Thus, performance degrades gracefully under</span></span><br><span class="line"><span class="comment">     * accidental or malicious usages in which hashCode() methods</span></span><br><span class="line"><span class="comment">     * return values that are poorly distributed, as well as those in</span></span><br><span class="line"><span class="comment">     * which many keys share a hashCode, so long as they are also</span></span><br><span class="line"><span class="comment">     * Comparable. (If neither of these apply, we may waste about a</span></span><br><span class="line"><span class="comment">     * factor of two in time and space compared to taking no</span></span><br><span class="line"><span class="comment">     * precautions. But the only known cases stem from poor user</span></span><br><span class="line"><span class="comment">     * programming practices that are already so slow that this makes</span></span><br><span class="line"><span class="comment">     * little difference.)</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * Because TreeNodes are about twice the size of regular nodes, we</span></span><br><span class="line"><span class="comment">     * use them only when bins contain enough nodes to warrant use</span></span><br><span class="line"><span class="comment">     * (see TREEIFY_THRESHOLD). And when they become too small (due to</span></span><br><span class="line"><span class="comment">     * removal or resizing) they are converted back to plain bins.  In</span></span><br><span class="line"><span class="comment">     * usages with well-distributed user hashCodes, tree bins are</span></span><br><span class="line"><span class="comment">     * rarely used.  Ideally, under random hashCodes, the frequency of</span></span><br><span class="line"><span class="comment">     * nodes in bins follows a Poisson distribution</span></span><br><span class="line"><span class="comment">     * (http://en.wikipedia.org/wiki/Poisson_distribution) with a</span></span><br><span class="line"><span class="comment">     * parameter of about 0.5 on average for the default resizing</span></span><br><span class="line"><span class="comment">     * threshold of 0.75, although with a large variance because of</span></span><br><span class="line"><span class="comment">     * resizing granularity. Ignoring variance, the expected</span></span><br><span class="line"><span class="comment">     * occurrences of list size k are (exp(-0.5) * pow(0.5, k) /</span></span><br><span class="line"><span class="comment">     * factorial(k)). The first values are:</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * 0:    0.60653066</span></span><br><span class="line"><span class="comment">     * 1:    0.30326533</span></span><br><span class="line"><span class="comment">     * 2:    0.07581633</span></span><br><span class="line"><span class="comment">     * 3:    0.01263606</span></span><br><span class="line"><span class="comment">     * 4:    0.00157952</span></span><br><span class="line"><span class="comment">     * 5:    0.00015795</span></span><br><span class="line"><span class="comment">     * 6:    0.00001316</span></span><br><span class="line"><span class="comment">     * 7:    0.00000094</span></span><br><span class="line"><span class="comment">     * 8:    0.00000006</span></span><br><span class="line"><span class="comment">     * more: less than 1 in ten million</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * The root of a tree bin is normally its first node.  However,</span></span><br><span class="line"><span class="comment">     * sometimes (currently only upon Iterator.remove), the root might</span></span><br><span class="line"><span class="comment">     * be elsewhere, but can be recovered following parent links</span></span><br><span class="line"><span class="comment">     * (method TreeNode.root()).</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * All applicable internal methods accept a hash code as an</span></span><br><span class="line"><span class="comment">     * argument (as normally supplied from a public method), allowing</span></span><br><span class="line"><span class="comment">     * them to call each other without recomputing user hashCodes.</span></span><br><span class="line"><span class="comment">     * Most internal methods also accept a &quot;tab&quot; argument, that is</span></span><br><span class="line"><span class="comment">     * normally the current table, but may be a new or old one when</span></span><br><span class="line"><span class="comment">     * resizing or converting.</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * When bin lists are treeified, split, or untreeified, we keep</span></span><br><span class="line"><span class="comment">     * them in the same relative access/traversal order (i.e., field</span></span><br><span class="line"><span class="comment">     * Node.next) to better preserve locality, and to slightly</span></span><br><span class="line"><span class="comment">     * simplify handling of splits and traversals that invoke</span></span><br><span class="line"><span class="comment">     * iterator.remove. When using comparators on insertion, to keep a</span></span><br><span class="line"><span class="comment">     * total ordering (or as close as is required here) across</span></span><br><span class="line"><span class="comment">     * rebalancings, we compare classes and identityHashCodes as</span></span><br><span class="line"><span class="comment">     * tie-breakers.</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * The use and transitions among plain vs tree modes is</span></span><br><span class="line"><span class="comment">     * complicated by the existence of subclass LinkedHashMap. See</span></span><br><span class="line"><span class="comment">     * below for hook methods defined to be invoked upon insertion,</span></span><br><span class="line"><span class="comment">     * removal and access that allow LinkedHashMap internals to</span></span><br><span class="line"><span class="comment">     * otherwise remain independent of these mechanics. (This also</span></span><br><span class="line"><span class="comment">     * requires that a map instance be passed to some utility methods</span></span><br><span class="line"><span class="comment">     * that may create new nodes.)</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * The concurrent-programming-like SSA-based coding style helps</span></span><br><span class="line"><span class="comment">     * avoid aliasing errors amid all of the twisty pointer operations.</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * The default initial capacity - MUST be a power of two. 必须是 2 的 n 次幂</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="comment">// 默认初始容量是 16</span></span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">int</span> <span class="variable">DEFAULT_INITIAL_CAPACITY</span> <span class="operator">=</span> <span class="number">1</span> &lt;&lt; <span class="number">4</span>; <span class="comment">// aka 16</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * The maximum capacity, used if a higher value is implicitly specified</span></span><br><span class="line"><span class="comment">     * by either of the constructors with arguments.</span></span><br><span class="line"><span class="comment">     * MUST be a power of two &lt;= 1&lt;&lt;30.</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="comment">// 数组的最大长度是 2^30</span></span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">int</span> <span class="variable">MAXIMUM_CAPACITY</span> <span class="operator">=</span> <span class="number">1</span> &lt;&lt; <span class="number">30</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * The load factor used when none specified in constructor.</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="comment">// 默认装载因子，和默认容量配合 16 * 0.75 = 12，所以真正可以存放元素的大小是 12，当数组中超过这个数之后就要进行一次扩容，精确扩容为 2 倍</span></span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">float</span> <span class="variable">DEFAULT_LOAD_FACTOR</span> <span class="operator">=</span> <span class="number">0.75f</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * The bin count threshold for using a tree rather than list for a</span></span><br><span class="line"><span class="comment">     * bin.  Bins are converted to trees when adding an element to a</span></span><br><span class="line"><span class="comment">     * bin with at least this many nodes. The value must be greater</span></span><br><span class="line"><span class="comment">     * than 2 and should be at least 8 to mesh with assumptions in</span></span><br><span class="line"><span class="comment">     * tree removal about conversion back to plain bins upon</span></span><br><span class="line"><span class="comment">     * shrinkage.</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="comment">// 转树，链表转换红黑树的阈值是 8，同时要求 table 的长度也要大于 64（MIN_TREEIFY_CAPACITY）才会转换红黑树</span></span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">int</span> <span class="variable">TREEIFY_THRESHOLD</span> <span class="operator">=</span> <span class="number">8</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * The bin count threshold for untreeifying a (split) bin during a</span></span><br><span class="line"><span class="comment">     * resize operation. Should be less than TREEIFY_THRESHOLD, and at</span></span><br><span class="line"><span class="comment">     * most 6 to mesh with shrinkage detection under removal.</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="comment">// 解树，红黑树退化为链表的阈值是 6</span></span><br><span class="line">    <span class="comment">// 这里为什么是 6，不是 7 呢？</span></span><br><span class="line">    <span class="comment">// 两层含义</span></span><br><span class="line">    <span class="comment">// 1. 当链表是 8 的时候刚转成红黑树，由于二叉树是一棵自平衡二叉搜索树，所以节点为 8 个时最后一层有一个元素，7 的时候正好是左右对称的，搜索性能最好，到 6 的时候可以考虑再变链表</span></span><br><span class="line">    <span class="comment">// 2. 懒加载的思想，第一次删除元素后我不变链表，第二次删除元素的时候再变，否则刚变成红黑树就要退化成链表，损耗性能。</span></span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">int</span> <span class="variable">UNTREEIFY_THRESHOLD</span> <span class="operator">=</span> <span class="number">6</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * The smallest table capacity for which bins may be treeified.</span></span><br><span class="line"><span class="comment">     * (Otherwise the table is resized if too many nodes in a bin.)</span></span><br><span class="line"><span class="comment">     * Should be at least 4 * TREEIFY_THRESHOLD to avoid conflicts</span></span><br><span class="line"><span class="comment">     * between resizing and treeification thresholds.</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="comment">// 转变红黑树的最小数组容量是 64</span></span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">int</span> <span class="variable">MIN_TREEIFY_CAPACITY</span> <span class="operator">=</span> <span class="number">64</span>;</span><br><span class="line"> </span><br><span class="line">    <span class="comment">// ...</span></span><br><span class="line">    </span><br><span class="line">    <span class="comment">/* ---------------- Fields -------------- */</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * The table, initialized on first use, and resized as</span></span><br><span class="line"><span class="comment">     * necessary. When allocated, length is always a power of two.</span></span><br><span class="line"><span class="comment">     * (We also tolerate length zero in some operations to allow</span></span><br><span class="line"><span class="comment">     * bootstrapping mechanics that are currently not needed.)</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="comment">// table 桶数组，存放 Node 节点</span></span><br><span class="line">    <span class="comment">// 这里用 transient 修饰，不能被序列化，但它还要被序列化，怎么做的呢？和 ArrayList 一样，都是自己实现了序列化方法 writeObject、readObject</span></span><br><span class="line">    <span class="keyword">transient</span> Node&lt;K,V&gt;[] table;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * Holds cached entrySet(). Note that AbstractMap fields are used</span></span><br><span class="line"><span class="comment">     * for keySet() and values().</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="comment">// 存储所有的键值对</span></span><br><span class="line">    <span class="keyword">transient</span> Set&lt;Map.Entry&lt;K,V&gt;&gt; entrySet;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * The number of key-value mappings contained in this map.</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="comment">// HashMap 的 size，记录有元素的节点</span></span><br><span class="line">    <span class="keyword">transient</span> <span class="type">int</span> size;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * The number of times this HashMap has been structurally modified</span></span><br><span class="line"><span class="comment">     * Structural modifications are those that change the number of mappings in</span></span><br><span class="line"><span class="comment">     * the HashMap or otherwise modify its internal structure (e.g.,</span></span><br><span class="line"><span class="comment">     * rehash).  This field is used to make iterators on Collection-views of</span></span><br><span class="line"><span class="comment">     * the HashMap fail-fast.  (See ConcurrentModificationException).</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="comment">// 修改次数</span></span><br><span class="line">    <span class="keyword">transient</span> <span class="type">int</span> modCount;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * The next size value at which to resize (capacity * load factor).</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@serial</span></span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="comment">// (The javadoc description is true upon serialization.</span></span><br><span class="line">    <span class="comment">// Additionally, if the table array has not been allocated, this</span></span><br><span class="line">    <span class="comment">// field holds the initial array capacity, or zero signifying</span></span><br><span class="line">    <span class="comment">// DEFAULT_INITIAL_CAPACITY.)</span></span><br><span class="line">    <span class="comment">// 下一次触发扩容的阈值</span></span><br><span class="line">    <span class="type">int</span> threshold;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * The load factor for the hash table.</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@serial</span></span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="comment">// 加载因子</span></span><br><span class="line">    <span class="keyword">final</span> <span class="type">float</span> loadFactor;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="【重点】Node-lt-K-V-gt-节点"><a href="#【重点】Node-lt-K-V-gt-节点" class="headerlink" title="【重点】Node&lt;K, V&gt; 节点"></a>【重点】Node&lt;K, V&gt; 节点</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Basic hash bin node, used for most entries.  (See below for</span></span><br><span class="line"><span class="comment"> * TreeNode subclass, and in LinkedHashMap for its Entry subclass.)</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">Node</span>&lt;K,V&gt; <span class="keyword">implements</span> <span class="title class_">Map</span>.Entry&lt;K,V&gt; &#123; <span class="comment">// 实现了 Map.Entry&lt;K,V&gt;</span></span><br><span class="line">    <span class="comment">// 为什么 hash 和 key 设置成 final</span></span><br><span class="line">    <span class="keyword">final</span> <span class="type">int</span> hash; <span class="comment">// 1. hash 值在一定程度上代表了对象的地址，内存地址是不能随便改变的 </span></span><br><span class="line">    <span class="comment">// 2. 同时在 32 位虚拟机的对象头 Mark Word 中有一个 15 位的 hash 值，4 位分代年龄 2 位锁标记位、1 位是否为偏向锁，对象头中的内容是不能改变的</span></span><br><span class="line">    </span><br><span class="line">    <span class="keyword">final</span> K key; <span class="comment">// 1. 而 key 不能修改，只能通过先删除再添加的方式 曲线救国 2. key 还会用于对比传入的 key 是否已经存在，不能随便修改</span></span><br><span class="line">    </span><br><span class="line">    V value; <span class="comment">// value 可以重新赋值的</span></span><br><span class="line">    Node&lt;K,V&gt; next; <span class="comment">// next 指针</span></span><br><span class="line"></span><br><span class="line">    Node(<span class="type">int</span> hash, K key, V value, Node&lt;K,V&gt; next) &#123; <span class="comment">// 构造器</span></span><br><span class="line">        <span class="built_in">this</span>.hash = hash;</span><br><span class="line">        <span class="built_in">this</span>.key = key;</span><br><span class="line">        <span class="built_in">this</span>.value = value;</span><br><span class="line">        <span class="built_in">this</span>.next = next;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">final</span> K <span class="title function_">getKey</span><span class="params">()</span>        &#123; <span class="keyword">return</span> key; &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">final</span> V <span class="title function_">getValue</span><span class="params">()</span>      &#123; <span class="keyword">return</span> value; &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">final</span> String <span class="title function_">toString</span><span class="params">()</span> &#123; <span class="keyword">return</span> key + <span class="string">&quot;=&quot;</span> + value; &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">final</span> <span class="type">int</span> <span class="title function_">hashCode</span><span class="params">()</span> &#123; <span class="comment">// 【重要】当前 node 的 hashCode也做了一次扰动处理，直接调用 Object 的 hashCode() 方法，将 key 的 hashcode 和 value 的 hashcode 做异或</span></span><br><span class="line">        <span class="keyword">return</span> Objects.hashCode(key) ^ Objects.hashCode(value); <span class="comment">// 异或的好处就是散列更加均匀</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">final</span> V <span class="title function_">setValue</span><span class="params">(V newValue)</span> &#123; <span class="comment">// 旧值用新值替换</span></span><br><span class="line">        <span class="type">V</span> <span class="variable">oldValue</span> <span class="operator">=</span> value;</span><br><span class="line">        value = newValue;</span><br><span class="line">        <span class="keyword">return</span> oldValue;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">final</span> <span class="type">boolean</span> <span class="title function_">equals</span><span class="params">(Object o)</span> &#123;</span><br><span class="line">        <span class="keyword">if</span> (o == <span class="built_in">this</span>)  <span class="comment">// 如果地址相等说明对象相等，则直接返回 true</span></span><br><span class="line">            <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">        <span class="keyword">if</span> (o <span class="keyword">instanceof</span> Map.Entry) &#123; <span class="comment">// 判断 o 的类型是 Map.Entry</span></span><br><span class="line">            Map.Entry&lt;?,?&gt; e = (Map.Entry&lt;?,?&gt;)o; <span class="comment">// 将 o 强转成 Map.Entry&lt;?,?&gt;，强转之后才能用 HashMap 的方法</span></span><br><span class="line">            <span class="keyword">if</span> (Objects.equals(key, e.getKey()) &amp;&amp;</span><br><span class="line">                Objects.equals(value, e.getValue())) <span class="comment">// 然后调用 Objects【不是 Object】 的 equals() 方法判断 key、value 和传入的 key、value 是否相等</span></span><br><span class="line">                <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// Objects 类</span></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Returns &#123;<span class="doctag">@code</span> true&#125; if the arguments are equal to each other</span></span><br><span class="line"><span class="comment"> * and &#123;<span class="doctag">@code</span> false&#125; otherwise.</span></span><br><span class="line"><span class="comment"> * Consequently, if both arguments are &#123;<span class="doctag">@code</span> null&#125;, &#123;<span class="doctag">@code</span> true&#125;</span></span><br><span class="line"><span class="comment"> * is returned and if exactly one argument is &#123;<span class="doctag">@code</span> null&#125;, &#123;<span class="doctag">@code</span></span></span><br><span class="line"><span class="comment"> * false&#125; is returned.  Otherwise, equality is determined by using</span></span><br><span class="line"><span class="comment"> * the &#123;<span class="doctag">@link</span> Object#equals equals&#125; method of the first</span></span><br><span class="line"><span class="comment"> * argument.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> a an object</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> b an object to be compared with &#123;<span class="doctag">@code</span> a&#125; for equality</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> &#123;<span class="doctag">@code</span> true&#125; if the arguments are equal to each other</span></span><br><span class="line"><span class="comment"> * and &#123;<span class="doctag">@code</span> false&#125; otherwise</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@see</span> Object#equals(Object)</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="type">boolean</span> <span class="title function_">equals</span><span class="params">(Object a, Object b)</span> &#123;</span><br><span class="line">    <span class="comment">// 先判断对象地址是否相等，再根据传入的 Object 的具体类型的 equals() 方法进行比较（如果这个类重写了 equals() 那就按重写的逻辑比较</span></span><br><span class="line">    <span class="comment">// 没有重写按 Object 的 equals() 还是比较对象地址）</span></span><br><span class="line">    <span class="keyword">return</span> (a == b) || (a != <span class="literal">null</span> &amp;&amp; a.equals(b)); </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="【重点】hash-Object-key"><a href="#【重点】hash-Object-key" class="headerlink" title="【重点】hash(Object key)"></a>【重点】hash(Object key)</h2><p>注意：&#x3D;&#x3D;null key 的哈希值是 0，不会调用 hashCode() 方法&#x3D;&#x3D;</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Computes key.hashCode() and spreads (XORs) higher bits of hash</span></span><br><span class="line"><span class="comment"> * to lower.  Because the table uses power-of-two masking, sets of</span></span><br><span class="line"><span class="comment"> * hashes that vary only in bits above the current mask will</span></span><br><span class="line"><span class="comment"> * always collide. (Among known examples are sets of Float keys</span></span><br><span class="line"><span class="comment"> * holding consecutive whole numbers in small tables.)  So we</span></span><br><span class="line"><span class="comment"> * apply a transform that spreads the impact of higher bits</span></span><br><span class="line"><span class="comment"> * downward. There is a tradeoff between speed, utility, and</span></span><br><span class="line"><span class="comment"> * quality of bit-spreading. Because many common sets of hashes</span></span><br><span class="line"><span class="comment"> * are already reasonably distributed (so don&#x27;t benefit from</span></span><br><span class="line"><span class="comment"> * spreading), and because we use trees to handle large sets of</span></span><br><span class="line"><span class="comment"> * collisions in bins, we just XOR some shifted bits in the</span></span><br><span class="line"><span class="comment"> * cheapest possible way to reduce systematic lossage, as well as</span></span><br><span class="line"><span class="comment"> * to incorporate impact of the highest bits that would otherwise</span></span><br><span class="line"><span class="comment"> * never be used in index calculations because of table bounds.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="comment">// 求 key 的哈希值，自身和右移 16 位做异或</span></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">final</span> <span class="type">int</span> <span class="title function_">hash</span><span class="params">(Object key)</span> &#123;</span><br><span class="line">    <span class="type">int</span> h;</span><br><span class="line">    <span class="comment">// null key 的哈希值是 0</span></span><br><span class="line">    <span class="keyword">return</span> (key == <span class="literal">null</span>) ? <span class="number">0</span> : (h = key.hashCode()) ^ (h &gt;&gt;&gt; <span class="number">16</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="comparableClassFor-Object-x"><a href="#comparableClassFor-Object-x" class="headerlink" title="comparableClassFor(Object x)"></a>comparableClassFor(Object x)</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Returns x&#x27;s Class if it is of the form &quot;class C implements</span></span><br><span class="line"><span class="comment"> * Comparable&lt;C&gt;&quot;, else null.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="comment">// 判断当前类 x 是否实现了 Comparable&lt;C&gt; 接口（是否进行比较），如果是返回当前类的 Class 对象，否则返回 null</span></span><br><span class="line"><span class="keyword">static</span> Class&lt;?&gt; comparableClassFor(Object x) &#123;</span><br><span class="line">    <span class="keyword">if</span> (x <span class="keyword">instanceof</span> Comparable) &#123; <span class="comment">// 类型判断</span></span><br><span class="line">        <span class="comment">// c 是 Class 对象，ts、as 是类型数组 (s) 复数，t 是类型并且是 ts 中的元素，p 是参数化类型（ArrayList&lt;String&gt;）</span></span><br><span class="line">        Class&lt;?&gt; c; Type[] ts, as; Type t; ParameterizedType p;</span><br><span class="line">        </span><br><span class="line">        <span class="comment">// 如果 x 的 Class 对象是 String 类型，直接返回类型 c。因为 String 类实现了 Comparable&lt;C&gt; 接口</span></span><br><span class="line">        <span class="keyword">if</span> ((c = x.getClass()) == String.class) <span class="comment">// bypass checks</span></span><br><span class="line">            <span class="keyword">return</span> c;</span><br><span class="line">        <span class="comment">// 获取实现的接口是否为空，并赋值给 ts【List, RandomAccess、Cloneable、Seriablizable】</span></span><br><span class="line">        <span class="keyword">if</span> ((ts = c.getGenericInterfaces()) != <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="keyword">for</span> (<span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> <span class="number">0</span>; i &lt; ts.length; ++i) &#123; <span class="comment">// 循环每个接口</span></span><br><span class="line">                <span class="keyword">if</span> (((t = ts[i]) <span class="keyword">instanceof</span> ParameterizedType) &amp;&amp; <span class="comment">// 判断当前接口是否是参数类类型的，即 List&lt;Object&gt; 形式</span></span><br><span class="line">                    ((p = (ParameterizedType)t).getRawType() ==</span><br><span class="line">                     Comparable.class) &amp;&amp;<span class="comment">// 且 判断这个参数化类型的外层【List】 是否 是 Comparable.class 类型</span></span><br><span class="line">                    (as = p.getActualTypeArguments()) != <span class="literal">null</span> &amp;&amp; <span class="comment">// 且 判断这个参数化类型的内层 【Object.class[]】是否为空</span></span><br><span class="line">                    as.length == <span class="number">1</span> &amp;&amp; as[<span class="number">0</span>] == c) <span class="comment">// type arg is c // 且内层数组的大小必须是 1 且第一个元素的类型是 c </span></span><br><span class="line">                    <span class="keyword">return</span> c; <span class="comment">// 才返回类型 c</span></span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> <span class="literal">null</span>; <span class="comment">// 否则返回 null</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="compareComparables-Class-lt-gt-kc-Object-k-Object-x"><a href="#compareComparables-Class-lt-gt-kc-Object-k-Object-x" class="headerlink" title="compareComparables(Class&lt;?&gt; kc, Object k, Object x) {"></a>compareComparables(Class&lt;?&gt; kc, Object k, Object x) {</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Returns k.compareTo(x) if x matches kc (k&#x27;s screened comparable</span></span><br><span class="line"><span class="comment"> * class), else 0.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="comment">// 对于对象 k，k 的类型是 kc，比较 k 和 x</span></span><br><span class="line"><span class="meta">@SuppressWarnings(&#123;&quot;rawtypes&quot;,&quot;unchecked&quot;&#125;)</span> <span class="comment">// for cast to Comparable</span></span><br><span class="line"><span class="keyword">static</span> <span class="type">int</span> <span class="title function_">compareComparables</span><span class="params">(Class&lt;?&gt; kc, Object k, Object x)</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> (x == <span class="literal">null</span> || x.getClass() != kc ? <span class="number">0</span> :</span><br><span class="line">            ((Comparable)k).compareTo(x));</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="【重点】tableSizeFor-int-cap"><a href="#【重点】tableSizeFor-int-cap" class="headerlink" title="【重点】tableSizeFor(int cap)"></a>【重点】tableSizeFor(int cap)</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Returns a power of two size for the given target capacity.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="comment">// 取出一个数字的最接近 2^n 次方的数（向上取整）</span></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">final</span> <span class="type">int</span> <span class="title function_">tableSizeFor</span><span class="params">(<span class="type">int</span> cap)</span> &#123;</span><br><span class="line">    <span class="type">int</span> <span class="variable">n</span> <span class="operator">=</span> cap - <span class="number">1</span>; <span class="comment">// 9</span></span><br><span class="line">    n |= n &gt;&gt;&gt; <span class="number">1</span>; <span class="comment">// 1001 | 0100 = 1101</span></span><br><span class="line">    n |= n &gt;&gt;&gt; <span class="number">2</span>; <span class="comment">// 1101 | 0011 = 1111</span></span><br><span class="line">    n |= n &gt;&gt;&gt; <span class="number">4</span>; <span class="comment">// 1111 | 0000 = 1111</span></span><br><span class="line">    n |= n &gt;&gt;&gt; <span class="number">8</span>; <span class="comment">// 1111</span></span><br><span class="line">    n |= n &gt;&gt;&gt; <span class="number">16</span>;<span class="comment">// 1111</span></span><br><span class="line">    <span class="keyword">return</span> (n &lt; <span class="number">0</span>) ? <span class="number">1</span> : (n &gt;= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + <span class="number">1</span>; <span class="comment">// n + 1 = 1 0000 = 2^4 = 16</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="HashMap-构造器"><a href="#HashMap-构造器" class="headerlink" title="HashMap 构造器"></a>HashMap 构造器</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* ---------------- Public operations -------------- */</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Constructs an empty &lt;tt&gt;HashMap&lt;/tt&gt; with the specified initial</span></span><br><span class="line"><span class="comment"> * capacity and load factor.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span>  initialCapacity the initial capacity</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span>  loadFactor      the load factor</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@throws</span> IllegalArgumentException if the initial capacity is negative</span></span><br><span class="line"><span class="comment"> *         or the load factor is nonpositive</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="comment">// 带初始容量和负载因子的构造器</span></span><br><span class="line"><span class="keyword">public</span> <span class="title function_">HashMap</span><span class="params">(<span class="type">int</span> initialCapacity, <span class="type">float</span> loadFactor)</span> &#123;</span><br><span class="line">    <span class="keyword">if</span> (initialCapacity &lt; <span class="number">0</span>) <span class="comment">// 初始容量小于 0 直接抛异常</span></span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">IllegalArgumentException</span>(<span class="string">&quot;Illegal initial capacity: &quot;</span> +</span><br><span class="line">                                           initialCapacity);</span><br><span class="line">    <span class="keyword">if</span> (initialCapacity &gt; MAXIMUM_CAPACITY) <span class="comment">// 初始容量大于 2^30 赋值给 2^30</span></span><br><span class="line">        initialCapacity = MAXIMUM_CAPACITY;</span><br><span class="line">    <span class="keyword">if</span> (loadFactor &lt;= <span class="number">0</span> || Float.isNaN(loadFactor)) <span class="comment">// 负载因子小于 0 或传入的不是一个数，直接抛异常</span></span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">IllegalArgumentException</span>(<span class="string">&quot;Illegal load factor: &quot;</span> +</span><br><span class="line">                                           loadFactor);</span><br><span class="line">    <span class="built_in">this</span>.loadFactor = loadFactor;</span><br><span class="line">    <span class="built_in">this</span>.threshold = tableSizeFor(initialCapacity); <span class="comment">// 否则将初始容量向上取最近的 2^n 次幂</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Constructs an empty &lt;tt&gt;HashMap&lt;/tt&gt; with the specified initial</span></span><br><span class="line"><span class="comment"> * capacity and the default load factor (0.75).</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span>  initialCapacity the initial capacity.</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@throws</span> IllegalArgumentException if the initial capacity is negative.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="comment">// 只带初始容量的构造器</span></span><br><span class="line"><span class="keyword">public</span> <span class="title function_">HashMap</span><span class="params">(<span class="type">int</span> initialCapacity)</span> &#123;</span><br><span class="line">    <span class="comment">// 调用的还是两个参数的构造器，只不过负载因子指定为默认的 0.75</span></span><br><span class="line">    <span class="built_in">this</span>(initialCapacity, DEFAULT_LOAD_FACTOR);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Constructs an empty &lt;tt&gt;HashMap&lt;/tt&gt; with the default initial capacity</span></span><br><span class="line"><span class="comment"> * (16) and the default load factor (0.75).</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="comment">// 空参构造器没有对 table 赋值（即 threshold 变量）</span></span><br><span class="line"><span class="keyword">public</span> <span class="title function_">HashMap</span><span class="params">()</span> &#123;</span><br><span class="line">    <span class="built_in">this</span>.loadFactor = DEFAULT_LOAD_FACTOR; <span class="comment">// all other fields defaulted</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Constructs a new &lt;tt&gt;HashMap&lt;/tt&gt; with the same mappings as the</span></span><br><span class="line"><span class="comment"> * specified &lt;tt&gt;Map&lt;/tt&gt;.  The &lt;tt&gt;HashMap&lt;/tt&gt; is created with</span></span><br><span class="line"><span class="comment"> * default load factor (0.75) and an initial capacity sufficient to</span></span><br><span class="line"><span class="comment"> * hold the mappings in the specified &lt;tt&gt;Map&lt;/tt&gt;.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span>   m the map whose mappings are to be placed in this map</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@throws</span>  NullPointerException if the specified map is null</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="comment">// 带 Map 参数构造器，用另一个 Map 初始化当前 HashMap</span></span><br><span class="line"><span class="keyword">public</span> <span class="title function_">HashMap</span><span class="params">(Map&lt;? extends K, ? extends V&gt; m)</span> &#123;</span><br><span class="line">    <span class="built_in">this</span>.loadFactor = DEFAULT_LOAD_FACTOR;</span><br><span class="line">    putMapEntries(m, <span class="literal">false</span>); <span class="comment">// evcit = false 表示第一次构造，否则 true</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="putMapEntries-Map-lt-extends-K-extends-V-gt-m-boolean-evict"><a href="#putMapEntries-Map-lt-extends-K-extends-V-gt-m-boolean-evict" class="headerlink" title="putMapEntries(Map&lt;? extends K, ? extends V&gt; m, boolean evict)"></a>putMapEntries(Map&lt;? extends K, ? extends V&gt; m, boolean evict)</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Implements Map.putAll and Map constructor</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> m the map</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> evict false when initially constructing this map, else</span></span><br><span class="line"><span class="comment"> * true (relayed to method afterNodeInsertion).</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">final</span> <span class="keyword">void</span> <span class="title function_">putMapEntries</span><span class="params">(Map&lt;? extends K, ? extends V&gt; m, <span class="type">boolean</span> evict)</span> &#123;</span><br><span class="line">    <span class="type">int</span> <span class="variable">s</span> <span class="operator">=</span> m.size();</span><br><span class="line">    <span class="keyword">if</span> (s &gt; <span class="number">0</span>) &#123;</span><br><span class="line">        <span class="comment">// 如果 table 是 null，则给 threshold 赋值</span></span><br><span class="line">        <span class="keyword">if</span> (table == <span class="literal">null</span>) &#123; <span class="comment">// pre-size</span></span><br><span class="line">            <span class="type">float</span> <span class="variable">ft</span> <span class="operator">=</span> ((<span class="type">float</span>)s / loadFactor) + <span class="number">1.0F</span>; <span class="comment">// 通过 元素个数 / 加载因子 反向得到容量，因为不能整除，所以保险起见向上取整</span></span><br><span class="line">            <span class="type">int</span> <span class="variable">t</span> <span class="operator">=</span> ((ft &lt; (<span class="type">float</span>)MAXIMUM_CAPACITY) ?</span><br><span class="line">                     (<span class="type">int</span>)ft : MAXIMUM_CAPACITY); <span class="comment">// float 转 int</span></span><br><span class="line">            <span class="keyword">if</span> (t &gt; threshold) <span class="comment">// 如果 m 需要的空间大小 t &gt; table 的大小 threshold，容量向上取最近的 2^n</span></span><br><span class="line">                threshold = tableSizeFor(t);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">else</span> <span class="keyword">if</span> (s &gt; threshold) <span class="comment">// 如果 table 不为空且 m 中的元素个数 s 大于table 的大小 threshold，放不下了就进行扩容</span></span><br><span class="line">            resize();</span><br><span class="line">        <span class="keyword">for</span> (Map.Entry&lt;? <span class="keyword">extends</span> <span class="title class_">K</span>, ? <span class="keyword">extends</span> <span class="title class_">V</span>&gt; e : m.entrySet()) &#123; <span class="comment">// 最后就是初始化，把 m 中的每个 key-value 放到 table 数组中</span></span><br><span class="line">            <span class="type">K</span> <span class="variable">key</span> <span class="operator">=</span> e.getKey();</span><br><span class="line">            <span class="type">V</span> <span class="variable">value</span> <span class="operator">=</span> e.getValue();</span><br><span class="line">            putVal(hash(key), key, value, <span class="literal">false</span>, evict); <span class="comment">// 调用私有的 putVal()</span></span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="【重点】get-Object-key"><a href="#【重点】get-Object-key" class="headerlink" title="【重点】get(Object key)"></a>【重点】get(Object key)</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Returns the value to which the specified key is mapped,</span></span><br><span class="line"><span class="comment"> * or &#123;<span class="doctag">@code</span> null&#125; if this map contains no mapping for the key.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * &lt;p&gt;More formally, if this map contains a mapping from a key</span></span><br><span class="line"><span class="comment"> * &#123;<span class="doctag">@code</span> k&#125; to a value &#123;<span class="doctag">@code</span> v&#125; such that &#123;<span class="doctag">@code</span> (key==null ? k==null :</span></span><br><span class="line"><span class="comment"> * key.equals(k))&#125;, then this method returns &#123;<span class="doctag">@code</span> v&#125;; otherwise</span></span><br><span class="line"><span class="comment"> * it returns &#123;<span class="doctag">@code</span> null&#125;.  (There can be at most one such mapping.)</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * &lt;p&gt;A return value of &#123;<span class="doctag">@code</span> null&#125; does not &lt;i&gt;necessarily&lt;/i&gt;</span></span><br><span class="line"><span class="comment"> * indicate that the map contains no mapping for the key; it&#x27;s also</span></span><br><span class="line"><span class="comment"> * possible that the map explicitly maps the key to &#123;<span class="doctag">@code</span> null&#125;.</span></span><br><span class="line"><span class="comment"> * The &#123;<span class="doctag">@link</span> #containsKey containsKey&#125; operation may be used to</span></span><br><span class="line"><span class="comment"> * distinguish these two cases.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@see</span> #put(Object, Object)</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="comment">// 根据 key 获取值</span></span><br><span class="line"><span class="keyword">public</span> V <span class="title function_">get</span><span class="params">(Object key)</span> &#123;</span><br><span class="line">    Node&lt;K,V&gt; e;</span><br><span class="line">    <span class="keyword">return</span> (e = getNode(hash(key), key)) == <span class="literal">null</span> ? <span class="literal">null</span> : e.value; <span class="comment">// 调用内部的 getNode() 方法</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Implements Map.get and related methods</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> hash hash for key</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> key the key</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> the node, or null if none</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="comment">// 根据 hash 值和 key 获取 Node 节点</span></span><br><span class="line"><span class="keyword">final</span> Node&lt;K,V&gt; <span class="title function_">getNode</span><span class="params">(<span class="type">int</span> hash, Object key)</span> &#123;</span><br><span class="line">    Node&lt;K,V&gt;[] tab; <span class="comment">// 定义的一个临时 Node 数组，用于存放 table 数组</span></span><br><span class="line">    Node&lt;K,V&gt; first, e; <span class="comment">// first 表示链表的头节点，e 是一个临时节点</span></span><br><span class="line">    <span class="type">int</span> n; K k;</span><br><span class="line">    <span class="keyword">if</span> ((tab = table) != <span class="literal">null</span> &amp;&amp; (n = tab.length) &gt; <span class="number">0</span> &amp;&amp; <span class="comment">// table 不为空</span></span><br><span class="line">        (first = tab[(n - <span class="number">1</span>) &amp; hash]) != <span class="literal">null</span>) &#123; <span class="comment">// 且 取出当前的节点 Node 不为空； tab[(n - 1) &amp; hash]，(n - 1) &amp; hash 定位底层数组的索引下标</span></span><br><span class="line">        <span class="comment">// hash 值相等且 key 相等 且 equals() 相等, 直接返回 first，</span></span><br><span class="line">        <span class="comment">// 为什么要三个判断呢？因为根据 hash 值相等不能判断两个对象相等</span></span><br><span class="line">        <span class="keyword">if</span> (first.hash == hash &amp;&amp; <span class="comment">// always check first node </span></span><br><span class="line">            ((k = first.key) == key || (key != <span class="literal">null</span> &amp;&amp; key.equals(k))))</span><br><span class="line">            <span class="keyword">return</span> first;</span><br><span class="line">        <span class="comment">// 否则比较头节点的下一个节点（可能是 Node、也可能是 TreeNode）</span></span><br><span class="line">        <span class="keyword">if</span> ((e = first.next) != <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="keyword">if</span> (first <span class="keyword">instanceof</span> TreeNode) <span class="comment">// 如果是 TreeNode，则从红黑树中查询 getTreeNode</span></span><br><span class="line">                <span class="keyword">return</span> ((TreeNode&lt;K,V&gt;)first).getTreeNode(hash, key);</span><br><span class="line">            <span class="comment">// 否则遍历链表，从链表里找</span></span><br><span class="line">            <span class="keyword">do</span> &#123;</span><br><span class="line">                <span class="keyword">if</span> (e.hash == hash &amp;&amp;</span><br><span class="line">                    ((k = e.key) == key || (key != <span class="literal">null</span> &amp;&amp; key.equals(k))))</span><br><span class="line">                    <span class="keyword">return</span> e;</span><br><span class="line">            &#125; <span class="keyword">while</span> ((e = e.next) != <span class="literal">null</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// 找不到就返回 null</span></span><br><span class="line">    <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="containsKey-Object-key"><a href="#containsKey-Object-key" class="headerlink" title="containsKey(Object key)"></a>containsKey(Object key)</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Returns &lt;tt&gt;true&lt;/tt&gt; if this map contains a mapping for the</span></span><br><span class="line"><span class="comment"> * specified key.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span>   key   The key whose presence in this map is to be tested</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> &lt;tt&gt;true&lt;/tt&gt; if this map contains a mapping for the specified</span></span><br><span class="line"><span class="comment"> * key.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="comment">// getNode() 返回值是 null 表示不存在，否则存在</span></span><br><span class="line"><span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">containsKey</span><span class="params">(Object key)</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> getNode(hash(key), key) != <span class="literal">null</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="【重点】put-K-key-V-value-添加和修改方法"><a href="#【重点】put-K-key-V-value-添加和修改方法" class="headerlink" title="【重点】put(K key, V value) 添加和修改方法"></a>【重点】put(K key, V value) 添加和修改方法</h2><p>通过看源码我们发现，如果 put 是修改的情况则会返回旧值，如果 put 是添加的话，最后添加成功返回 null</p><p>根据这个特性，我们在需要<strong>确保唯一的 key 的业务场景下</strong>，就可以使用这个返回值来判断在业务执行的过程中 key 到底是不是唯一的，如果出现了不唯一的情况抛出异常，排查问题。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Associates the specified value with the specified key in this map.</span></span><br><span class="line"><span class="comment"> * If the map previously contained a mapping for the key, the old</span></span><br><span class="line"><span class="comment"> * value is replaced.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> key key with which the specified value is to be associated</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> value value to be associated with the specified key</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> the previous value associated with &lt;tt&gt;key&lt;/tt&gt;, or</span></span><br><span class="line"><span class="comment"> *         &lt;tt&gt;null&lt;/tt&gt; if there was no mapping for &lt;tt&gt;key&lt;/tt&gt;.</span></span><br><span class="line"><span class="comment"> *         (A &lt;tt&gt;null&lt;/tt&gt; return can also indicate that the map</span></span><br><span class="line"><span class="comment"> *         previously associated &lt;tt&gt;null&lt;/tt&gt; with &lt;tt&gt;key&lt;/tt&gt;.)</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> V <span class="title function_">put</span><span class="params">(K key, V value)</span> &#123;</span><br><span class="line">    <span class="comment">// 调用 putVal</span></span><br><span class="line">    <span class="keyword">return</span> putVal(hash(key), key, value, <span class="literal">false</span>, <span class="literal">true</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Implements Map.put and related methods</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> hash hash for key</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> key the key</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> value the value to put</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> onlyIfAbsent if true, don&#x27;t change existing value</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> evict if false, the table is in creation mode.</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> previous value, or null if none</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="comment">// 真正的 put</span></span><br><span class="line"><span class="keyword">final</span> V <span class="title function_">putVal</span><span class="params">(<span class="type">int</span> hash, K key, V value, <span class="type">boolean</span> onlyIfAbsent,</span></span><br><span class="line"><span class="params">               <span class="type">boolean</span> evict)</span> &#123;</span><br><span class="line">    </span><br><span class="line">    Node&lt;K,V&gt;[] tab; <span class="comment">// table 数组的副本</span></span><br><span class="line">    Node&lt;K,V&gt; p; <span class="comment">// p 是桶下标的头节点</span></span><br><span class="line">    <span class="type">int</span> n, i; <span class="comment">// n 是 table 数组的大小</span></span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 如果 table 是 null 或者 table 没有元素</span></span><br><span class="line">    <span class="keyword">if</span> ((tab = table) == <span class="literal">null</span> || (n = tab.length) == <span class="number">0</span>) </span><br><span class="line">        n = (tab = resize()).length; <span class="comment">// 进行一次扩容，第一次就是 16 赋值给 n</span></span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 此时 table 不为 null，定位桶下标</span></span><br><span class="line">    <span class="comment">// 如果当前槽位上没有数据，直接放进去</span></span><br><span class="line">    <span class="keyword">if</span> ((p = tab[i = (n - <span class="number">1</span>) &amp; hash]) == <span class="literal">null</span>)</span><br><span class="line">        tab[i] = newNode(hash, key, value, <span class="literal">null</span>);</span><br><span class="line">    <span class="comment">// 否则说明当前槽位上有数据</span></span><br><span class="line">    <span class="keyword">else</span> &#123;</span><br><span class="line">        Node&lt;K,V&gt; e; K k;</span><br><span class="line">        <span class="comment">// 如果头节点的 key 就是就是传入的 key，则直接将头节点 p 赋值给 e</span></span><br><span class="line">        <span class="keyword">if</span> (p.hash == hash &amp;&amp;</span><br><span class="line">            ((k = p.key) == key || (key != <span class="literal">null</span> &amp;&amp; key.equals(k))))</span><br><span class="line">            e = p;</span><br><span class="line">        <span class="comment">// 如果头节点 p 是红黑树节点，则需要进行 TreeNode 的添加</span></span><br><span class="line">        <span class="keyword">else</span> <span class="keyword">if</span> (p <span class="keyword">instanceof</span> TreeNode)</span><br><span class="line">            e = ((TreeNode&lt;K,V&gt;)p).putTreeVal(<span class="built_in">this</span>, tab, hash, key, value);</span><br><span class="line">        <span class="comment">// 否则那就是链表形式，而且头节点的 key 不是传入的 key</span></span><br><span class="line">        <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="comment">// 遍历链表</span></span><br><span class="line">            <span class="keyword">for</span> (<span class="type">int</span> <span class="variable">binCount</span> <span class="operator">=</span> <span class="number">0</span>; ; ++binCount) &#123;</span><br><span class="line">                <span class="keyword">if</span> ((e = p.next) == <span class="literal">null</span>) &#123; <span class="comment">// 如果当前节点的 next 是空，则尾插法插入传入的节点，结束 put</span></span><br><span class="line">                    p.next = newNode(hash, key, value, <span class="literal">null</span>);</span><br><span class="line">                    <span class="comment">// 当链表长度达到 8，执行 treeifyBin() 链表转红黑树，至于最终转不转还要 table 的长度是否大于 64，大于才转，否则执行扩容</span></span><br><span class="line">                    <span class="keyword">if</span> (binCount &gt;= TREEIFY_THRESHOLD - <span class="number">1</span>) <span class="comment">// -1 for 1st </span></span><br><span class="line">                        treeifyBin(tab, hash);</span><br><span class="line">                    <span class="keyword">break</span>;</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="comment">// 否则如果找到了 key 相同的节点，也要结束 put</span></span><br><span class="line">                <span class="keyword">if</span> (e.hash == hash &amp;&amp;</span><br><span class="line">                    ((k = e.key) == key || (key != <span class="literal">null</span> &amp;&amp; key.equals(k))))</span><br><span class="line">                    <span class="keyword">break</span>;</span><br><span class="line">                p = e; <span class="comment">// 否则 p = (e = p.next) 其实就是 p = p.next</span></span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// 如果 e 不为 null 说明从 HashMap 中找到了这个 key 对应的节点，那么执行修改逻辑，修改 key 对应的值</span></span><br><span class="line">        <span class="keyword">if</span> (e != <span class="literal">null</span>) &#123; <span class="comment">// existing mapping for key</span></span><br><span class="line">            <span class="type">V</span> <span class="variable">oldValue</span> <span class="operator">=</span> e.value;</span><br><span class="line">            <span class="keyword">if</span> (!onlyIfAbsent || oldValue == <span class="literal">null</span>) <span class="comment">// onlyIfAbsent 如果是 true 则不能修改</span></span><br><span class="line">                e.value = value;</span><br><span class="line">            afterNodeAccess(e);</span><br><span class="line">            <span class="keyword">return</span> oldValue; <span class="comment">// 修改完返回旧值</span></span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    ++modCount; <span class="comment">// 修改数 + 1</span></span><br><span class="line">    </span><br><span class="line">   <span class="comment">// 注意：HashMap 是先添加再扩容</span></span><br><span class="line">    <span class="keyword">if</span> (++size &gt; threshold) <span class="comment">// 如果元素个数超过扩容阈值，进行扩容</span></span><br><span class="line">        resize();</span><br><span class="line">    afterNodeInsertion(evict);</span><br><span class="line">    <span class="keyword">return</span> <span class="literal">null</span>; <span class="comment">// 如果添加成功则返回 null</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 如果 put 的 key 存在且 value 不是 null 就不覆盖这个 value</span></span><br><span class="line"><span class="comment">// 如果 key 存在且 value 是 null，则覆盖这个 value</span></span><br><span class="line"><span class="comment">// 如果 key 不存在就直接添加</span></span><br><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="keyword">public</span> V <span class="title function_">putIfAbsent</span><span class="params">(K key, V value)</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> putVal(hash(key), key, value, <span class="literal">true</span>, <span class="literal">true</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h2 id="resize-扩容方法"><a href="#resize-扩容方法" class="headerlink" title="resize() 扩容方法"></a>resize() 扩容方法</h2><p>思考题：HashMap 最多能放多少个元素呢？</p><p>和底层数组 table 的大小有关，与 threshold 没有关系，threshold 只有扩容有关，它的大小不会限制其他的操作。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Initializes or doubles table size.  If null, allocates in</span></span><br><span class="line"><span class="comment"> * accord with initial capacity target held in field threshold.</span></span><br><span class="line"><span class="comment"> * Otherwise, because we are using power-of-two expansion, the</span></span><br><span class="line"><span class="comment"> * elements from each bin must either stay at same index, or move</span></span><br><span class="line"><span class="comment"> * with a power of two offset in the new table.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> the table</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">final</span> Node&lt;K,V&gt;[] resize() &#123;</span><br><span class="line">    Node&lt;K,V&gt;[] oldTab = table; <span class="comment">// oldTable 表示原来的 table，做一个副本</span></span><br><span class="line">    <span class="type">int</span> <span class="variable">oldCap</span> <span class="operator">=</span> (oldTab == <span class="literal">null</span>) ? <span class="number">0</span> : oldTab.length; <span class="comment">// 如果 oldTable 的长度是空容量为 0，否则容量为 length</span></span><br><span class="line">    <span class="type">int</span> <span class="variable">oldThr</span> <span class="operator">=</span> threshold; <span class="comment">// oldThr 表示原 table 的 threshold (= length * load_factor)</span></span><br><span class="line">    <span class="type">int</span> newCap, newThr = <span class="number">0</span>; <span class="comment">//定义 新 table 的容量和阈值</span></span><br><span class="line">    <span class="keyword">if</span> (oldCap &gt; <span class="number">0</span>)  <span class="comment">// 如果 oldTable 容量 oldCap 大于 0</span></span><br><span class="line">        <span class="keyword">if</span> (oldCap &gt;= MAXIMUM_CAPACITY) &#123; <span class="comment">// 如果旧容量大于 2^30，放弃扩容，直接修改 threshold</span></span><br><span class="line">            threshold = Integer.MAX_VALUE; <span class="comment">// threshold 直接赋值为 INT_MAX</span></span><br><span class="line">            <span class="keyword">return</span> oldTab; <span class="comment">// 返回了旧 table</span></span><br><span class="line">        &#125;</span><br><span class="line">    <span class="comment">// 继续扩容</span></span><br><span class="line">        <span class="keyword">else</span> <span class="keyword">if</span> ((newCap = oldCap &lt;&lt; <span class="number">1</span>) &lt; MAXIMUM_CAPACITY &amp;&amp; <span class="comment">// 首先就是扩容为两倍 且 小于 2^30 次方</span></span><br><span class="line">                 oldCap &gt;= DEFAULT_INITIAL_CAPACITY) <span class="comment">// 且 旧容量 大于等于 初始容量</span></span><br><span class="line">            newThr = oldThr &lt;&lt; <span class="number">1</span>; <span class="comment">// double threshold // newThr (新的 threshold) 变成原来 oldThr 的两倍</span></span><br><span class="line">    &#125;</span><br><span class="line"><span class="comment">// 否则 oldTable 容量 oldCap 小于等于 0</span></span><br><span class="line">    <span class="keyword">else</span> <span class="keyword">if</span> (oldThr &gt; <span class="number">0</span>) <span class="comment">// initial capacity was placed in threshold // oldThr 大于 0</span></span><br><span class="line">        newCap = oldThr; <span class="comment">// 新容量 newCap 赋值为 oldThr</span></span><br><span class="line"><span class="comment">// 否则 oldTable 容量 oldCap 小于等于 0 且阈值 oldThr 也是小于等于 0，那么就用默认值</span></span><br><span class="line">    <span class="keyword">else</span> &#123;               <span class="comment">// zero initial threshold signifies using defaults</span></span><br><span class="line">        newCap = DEFAULT_INITIAL_CAPACITY; <span class="comment">// 新容量 newCap 为默认初始容量 64</span></span><br><span class="line">        newThr = (<span class="type">int</span>)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY); <span class="comment">// 新阈值 newThr 为默认加载因子 * 默认初始容量</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (newThr == <span class="number">0</span>) &#123;<span class="comment">// 如果信阈值为 0</span></span><br><span class="line">        <span class="type">float</span> <span class="variable">ft</span> <span class="operator">=</span> (<span class="type">float</span>)newCap * loadFactor; <span class="comment">// 得到 HashMap 实际可以使用的大小，即阈值</span></span><br><span class="line">        newThr = (newCap &lt; MAXIMUM_CAPACITY &amp;&amp; ft &lt; (<span class="type">float</span>)MAXIMUM_CAPACITY ? </span><br><span class="line">                  (<span class="type">int</span>)ft : Integer.MAX_VALUE); <span class="comment">// 新容量小于最大容量 2^30 且 ft 也要小于 2^30，此时新的阈值 newThr 等于 ft，否则就取 int 最大值</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// -------------------</span></span><br><span class="line"></span><br><span class="line">    threshold = newThr; <span class="comment">// 真正的给 threshold 进行 newThr 的赋值</span></span><br><span class="line">    <span class="meta">@SuppressWarnings(&#123;&quot;rawtypes&quot;,&quot;unchecked&quot;&#125;)</span></span><br><span class="line">        Node&lt;K,V&gt;[] newTab = (Node&lt;K,V&gt;[])<span class="keyword">new</span> <span class="title class_">Node</span>[newCap]; <span class="comment">// 创建扩容两倍后的 table</span></span><br><span class="line">    table = newTab; <span class="comment">// 真正的给 table 进行 newTab 的赋值</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// -----节点的迁移（原位置和新位置）----</span></span><br><span class="line"><span class="comment">// 如果 oldTable 不为空，则进行节点迁移，否则直接返回扩容后的 newTable</span></span><br><span class="line">    <span class="keyword">if</span> (oldTab != <span class="literal">null</span>) &#123;</span><br><span class="line">        <span class="keyword">for</span> (<span class="type">int</span> <span class="variable">j</span> <span class="operator">=</span> <span class="number">0</span>; j &lt; oldCap; ++j) &#123; <span class="comment">// for 循环取每个节点</span></span><br><span class="line">            Node&lt;K,V&gt; e;  <span class="comment">// e 用于存放 oldTable 的每个节点</span></span><br><span class="line">            <span class="keyword">if</span> ((e = oldTab[j]) != <span class="literal">null</span>) &#123; <span class="comment">// 如果 e 不是空</span></span><br><span class="line">                oldTab[j] = <span class="literal">null</span>; <span class="comment">// 则将 oldTable[j] 的内容置空，方便 gc，真正的值已经存到 e 中了</span></span><br><span class="line">                <span class="keyword">if</span> (e.next == <span class="literal">null</span>) <span class="comment">// 如果 e.next 为空，说明 e 是槽位上的头节点</span></span><br><span class="line">                    newTab[e.hash &amp; (newCap - <span class="number">1</span>)] = e; <span class="comment">// 则直接插入到 newTabale 对应的槽位上</span></span><br><span class="line">                <span class="keyword">else</span> <span class="keyword">if</span> (e <span class="keyword">instanceof</span> TreeNode) <span class="comment">// 否则如果 e 是树节点，则进行【拆分树】</span></span><br><span class="line">                    <span class="comment">// 如果进行 HashMap 扩容，我们的树肯定会被拆掉，会产生一定性能消耗</span></span><br><span class="line">                    <span class="comment">// 实际情况下，我们的 HashMap 很难达到红黑树。1. hash 十分散列 2. 业务中 不可能、不能够、不允许 在一个 map 中放这么多元素</span></span><br><span class="line">                    <span class="comment">// 如果我需要从 db 中取出 2^30 个数据，需要用 HashMap 进行处理，怎么办？</span></span><br><span class="line">                    <span class="comment">// 想到 ArrayList 的 clear() 方法，能够复用，不需要再次扩容</span></span><br><span class="line">                    <span class="comment">// 【重要】HashMap 也是如此，利用 clear() 方法进行分批处理，再 clear() 再放数据，只需要扩容一次</span></span><br><span class="line">                    ((TreeNode&lt;K,V&gt;)e).split(<span class="built_in">this</span>, newTab, j, oldCap);</span><br><span class="line">                <span class="keyword">else</span> &#123; <span class="comment">// preserve order // 否则链表上不止一个节点就需要遍历链表</span></span><br><span class="line">                    Node&lt;K,V&gt; loHead = <span class="literal">null</span>, loTail = <span class="literal">null</span>; <span class="comment">// loHead 是 old 链表的头节点，loTail 是 old 链表的尾节点</span></span><br><span class="line">                    Node&lt;K,V&gt; hiHead = <span class="literal">null</span>, hiTail = <span class="literal">null</span>; <span class="comment">// hiHead 是 new 链表的头节点，hiTail 是 new 链表的尾节点</span></span><br><span class="line">                    Node&lt;K,V&gt; next; <span class="comment">// 记录 next 节点</span></span><br><span class="line">                    </span><br><span class="line">                    <span class="comment">// 【创建链表】</span></span><br><span class="line">                    <span class="comment">// do while 循环遍历链表，分别建立了两个链表，一个 old 链表，一个 new 链表</span></span><br><span class="line">                    <span class="comment">// old 链表存的是位置不变的节点，new 链表是需要变化位置的节点</span></span><br><span class="line">                    <span class="keyword">do</span> &#123; </span><br><span class="line">                        next = e.next; <span class="comment">// 记录 next 节点</span></span><br><span class="line">                        <span class="keyword">if</span> ((e.hash &amp; oldCap) == <span class="number">0</span>) &#123; <span class="comment">// 如果当前节点的 hash 值 &amp; 旧容量 等于 0，则位置不变</span></span><br><span class="line">                            <span class="keyword">if</span> (loTail == <span class="literal">null</span>) <span class="comment">// 如果尾节点是空，说明链表为空，那么 e 就是 old 链表的头节点</span></span><br><span class="line">                                loHead = e;</span><br><span class="line">                            <span class="keyword">else</span></span><br><span class="line">                                loTail.next = e; <span class="comment">// 【尾插法】否则将 e 插入尾节点后面</span></span><br><span class="line">                            loTail = e; <span class="comment">// 最后更新尾节点为 e</span></span><br><span class="line">                        &#125;</span><br><span class="line">                        <span class="keyword">else</span> &#123; <span class="comment">// 否则，变化位置，将该元素放在新链表中</span></span><br><span class="line">                            <span class="keyword">if</span> (hiTail == <span class="literal">null</span>) <span class="comment">// 如果尾节点是空，说明链表为空，那么 e 就是 new 链表的头节点</span></span><br><span class="line">                                hiHead = e;</span><br><span class="line">                            <span class="keyword">else</span></span><br><span class="line">                                hiTail.next = e; <span class="comment">// 【尾插法】否则将 e 插入尾节点后面</span></span><br><span class="line">                            hiTail = e; <span class="comment">// 最后更新尾节点为 e</span></span><br><span class="line">                        &#125;</span><br><span class="line">                    &#125; <span class="keyword">while</span> ((e = next) != <span class="literal">null</span>);</span><br><span class="line">                    </span><br><span class="line">                    <span class="comment">// 【真正添加到 newTable 中】</span></span><br><span class="line">                    <span class="comment">// old 链表尾部最终判断</span></span><br><span class="line">                    <span class="keyword">if</span> (loTail != <span class="literal">null</span>) &#123; <span class="comment">// 如果 old 链表的尾节点 loTail 不为空，说明旧链表有元素（里面就是那些位置不变的节点），则将其置为空，并且将旧链表放到 newTable 的对应对应槽位上</span></span><br><span class="line">                        loTail.next = <span class="literal">null</span>;</span><br><span class="line">                        newTab[j] = loHead; <span class="comment">// 按照 oldTable 的位置不变，将旧链表的头节点 loHead 挂到 newTable 的槽位 j 上</span></span><br><span class="line">                    &#125;</span><br><span class="line">                    <span class="comment">// new 链表尾部最终判断</span></span><br><span class="line">                    <span class="keyword">if</span> (hiTail != <span class="literal">null</span>) &#123; <span class="comment">// 如果 new 链表的尾节点 loTail 不为空，说明新链表有元素（里面就是位置需要变化的节点），则将其置为空，并且将旧链表放到 newTable 的对应对应槽位上</span></span><br><span class="line">                        hiTail.next = <span class="literal">null</span>;</span><br><span class="line">                        newTab[j + oldCap] = hiHead; <span class="comment">// 将新链表的头节点 hiHead 挂到 newTable 的 j + oldCap 槽位上，所以位置由原来的 j 变到了 j + oldCap</span></span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"><span class="comment">// 最后返回 newTable</span></span><br><span class="line">    <span class="keyword">return</span> newTab;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="clear-清空元素，但容量不变，可以复用"><a href="#clear-清空元素，但容量不变，可以复用" class="headerlink" title="clear() 清空元素，但容量不变，可以复用"></a>clear() 清空元素，但容量不变，可以复用</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Removes all of the mappings from this map.</span></span><br><span class="line"><span class="comment"> * The map will be empty after this call returns.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">clear</span><span class="params">()</span> &#123;</span><br><span class="line">    Node&lt;K,V&gt;[] tab;</span><br><span class="line">    modCount++;</span><br><span class="line">    <span class="keyword">if</span> ((tab = table) != <span class="literal">null</span> &amp;&amp; size &gt; <span class="number">0</span>) &#123;</span><br><span class="line">        size = <span class="number">0</span>; <span class="comment">// 元素个数置为 0，但是容量没变</span></span><br><span class="line">        <span class="keyword">for</span> (<span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> <span class="number">0</span>; i &lt; tab.length; ++i)</span><br><span class="line">            tab[i] = <span class="literal">null</span>; <span class="comment">// 清空每个槽位</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="getOrDefault-key-defaultValue"><a href="#getOrDefault-key-defaultValue" class="headerlink" title="getOrDefault(key, defaultValue)"></a>getOrDefault(key, defaultValue)</h2><h3 id="Map-接口的-getOrDefault-key-defaultValue-实现"><a href="#Map-接口的-getOrDefault-key-defaultValue-实现" class="headerlink" title="Map 接口的 getOrDefault(key, defaultValue) 实现"></a>Map 接口的 getOrDefault(key, defaultValue) 实现</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Returns the value to which the specified key is mapped, or</span></span><br><span class="line"><span class="comment"> * &#123;<span class="doctag">@code</span> defaultValue&#125; if this map contains no mapping for the key.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@implSpec</span></span></span><br><span class="line"><span class="comment"> * The default implementation makes no guarantees about synchronization</span></span><br><span class="line"><span class="comment"> * or atomicity properties of this method. Any implementation providing</span></span><br><span class="line"><span class="comment"> * atomicity guarantees must override this method and document its</span></span><br><span class="line"><span class="comment"> * concurrency properties.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> key the key whose associated value is to be returned</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> defaultValue the default mapping of the key</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> the value to which the specified key is mapped, or</span></span><br><span class="line"><span class="comment"> * &#123;<span class="doctag">@code</span> defaultValue&#125; if this map contains no mapping for the key</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@throws</span> ClassCastException if the key is of an inappropriate type for</span></span><br><span class="line"><span class="comment"> * this map</span></span><br><span class="line"><span class="comment"> * (&lt;a href=&quot;&#123;<span class="doctag">@docRoot</span>&#125;/java/util/Collection.html#optional-restrictions&quot;&gt;optional&lt;/a&gt;)</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@throws</span> NullPointerException if the specified key is null and this map</span></span><br><span class="line"><span class="comment"> * does not permit null keys</span></span><br><span class="line"><span class="comment"> * (&lt;a href=&quot;&#123;<span class="doctag">@docRoot</span>&#125;/java/util/Collection.html#optional-restrictions&quot;&gt;optional&lt;/a&gt;)</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@since</span> 1.8</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">default</span> V <span class="title function_">getOrDefault</span><span class="params">(Object key, V defaultValue)</span> &#123;</span><br><span class="line">    V v;</span><br><span class="line">    <span class="comment">// 两个判断：1. 先判断值是否为 null  2. 再判断是否包含 key</span></span><br><span class="line">    <span class="comment">// 这里的 get(key) 调用的是子类的实现</span></span><br><span class="line">    <span class="keyword">return</span> (((v = get(key)) != <span class="literal">null</span>) || containsKey(key))</span><br><span class="line">        ? v</span><br><span class="line">        : defaultValue;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="HashMap-接口的-getOrDefault-key-defaultValue-实现"><a href="#HashMap-接口的-getOrDefault-key-defaultValue-实现" class="headerlink" title="HashMap 接口的 getOrDefault(key, defaultValue) 实现"></a>HashMap 接口的 getOrDefault(key, defaultValue) 实现</h3><p>和 Map 接口的实现不一样，HashMap 直接通过 getNode() 判断节点是否为 null</p><p>同时我们的 HashMap 是允许 null key 和 null value 的，但只允许一个 null key，而且 &#x3D;&#x3D;null key 的散列位置在 0 号位置&#x3D;&#x3D; </p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Overrides of JDK8 Map extension methods</span></span><br><span class="line"></span><br><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="keyword">public</span> V <span class="title function_">getOrDefault</span><span class="params">(Object key, V defaultValue)</span> &#123;</span><br><span class="line">    Node&lt;K,V&gt; e;</span><br><span class="line">    <span class="comment">// 只有一个判断：判断通过 key 获取到的 Node 是否为空，如果是空返回默认值，否则返回 value</span></span><br><span class="line">    <span class="keyword">return</span> (e = getNode(hash(key), key)) == <span class="literal">null</span> ? defaultValue : e.value;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="treeifyBin-Node-lt-K-V-gt-tab-int-hash-链表树化"><a href="#treeifyBin-Node-lt-K-V-gt-tab-int-hash-链表树化" class="headerlink" title="treeifyBin(Node&lt;K,V&gt;[] tab, int hash) 链表树化"></a>treeifyBin(Node&lt;K,V&gt;[] tab, int hash) 链表树化</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Replaces all linked nodes in bin at index for given hash unless</span></span><br><span class="line"><span class="comment"> * table is too small, in which case resizes instead.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="comment">// 树化方法：链表转红黑树，tab 就是底层数组，hash 是当前槽位上的链表 hash 值，它们的哈希值都是相等的</span></span><br><span class="line"><span class="keyword">final</span> <span class="keyword">void</span> <span class="title function_">treeifyBin</span><span class="params">(Node&lt;K,V&gt;[] tab, <span class="type">int</span> hash)</span> &#123;</span><br><span class="line">    <span class="type">int</span> n, index; Node&lt;K,V&gt; e;</span><br><span class="line">    <span class="keyword">if</span> (tab == <span class="literal">null</span> || (n = tab.length) &lt; MIN_TREEIFY_CAPACITY) <span class="comment">// 如果 table 为空 或者 table 的容量小于 64</span></span><br><span class="line">        resize();</span><br><span class="line">    <span class="keyword">else</span> <span class="keyword">if</span> ((e = tab[index = (n - <span class="number">1</span>) &amp; hash]) != <span class="literal">null</span>) &#123; <span class="comment">// 判断链表头节点是否为空，并把头节点赋值给 e，此时 e 的类型还是链表节点 Node</span></span><br><span class="line">        TreeNode&lt;K,V&gt; hd = <span class="literal">null</span>, tl = <span class="literal">null</span>; <span class="comment">// 定义红黑树节点变量 hd：可以理解为树的根节点（双向链表的尾节点），tl：树的尾节点（双向链表的尾节点）</span></span><br><span class="line">        </span><br><span class="line">        <span class="comment">// do while 循环把单链表 Node 替换成 TreeNode，同时把单链表变成了双链表</span></span><br><span class="line">        <span class="keyword">do</span> &#123;</span><br><span class="line">            TreeNode&lt;K,V&gt; p = replacementTreeNode(e, <span class="literal">null</span>); <span class="comment">// 每次把链表节点 e 转换成 TreeNode</span></span><br><span class="line">            <span class="keyword">if</span> (tl == <span class="literal">null</span>) <span class="comment">// 第一次 do while，tl = null，只会执行一次</span></span><br><span class="line">                hd = p; <span class="comment">// 将链表头节点对应的 TreeNode 赋值给 hd（可以理解为根节点）</span></span><br><span class="line">            <span class="keyword">else</span> &#123; <span class="comment">// 除了第一次之外，都需要建立前后两个节点之间的关系</span></span><br><span class="line">                <span class="comment">// ------- 卧槽，这是干啥呢？将单链表形式的 TreeNode 转换成双链表形式的 TreeNode</span></span><br><span class="line">                p.prev = tl; <span class="comment">// 当前节点 p 的前一个节点 指向 尾节点 tl</span></span><br><span class="line">                tl.next = p; <span class="comment">// 尾节点 tl 的下一个节点 指向 当前节点 p</span></span><br><span class="line">            &#125;</span><br><span class="line">            tl = p; <span class="comment">// 树的尾节点赋值为当前节点 p</span></span><br><span class="line">        &#125; <span class="keyword">while</span> ((e = e.next) != <span class="literal">null</span>); <span class="comment">// e = e.next 遍历单链表</span></span><br><span class="line">        </span><br><span class="line">        <span class="comment">// 将树根节点 hd 替换到要树化的槽位上</span></span><br><span class="line">        <span class="keyword">if</span> ((tab[index] = hd) != <span class="literal">null</span>)</span><br><span class="line">            <span class="comment">// 传入 table，调用 TreeNode 内部的 treeify 执行真正的树化逻辑</span></span><br><span class="line">            hd.treeify(tab);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// For treeifyBin</span></span><br><span class="line">TreeNode&lt;K,V&gt; <span class="title function_">replacementTreeNode</span><span class="params">(Node&lt;K,V&gt; p, Node&lt;K,V&gt; next)</span> &#123;</span><br><span class="line">    <span class="comment">// 通过 hash、key、value、next 创建一个 TreeNode</span></span><br><span class="line">    <span class="comment">// 通过查看源码发现 TreeNode 是 Node 的子类，TreeNode 中没有 next 指针，但是 Node 中有</span></span><br><span class="line">    <span class="comment">// 我们知道二叉树节点只需要一个 left 和 right 就够了，为什么还需要一个 next 指针呢？这样设计的好处是什么？</span></span><br><span class="line">    <span class="comment">// 【重点】这个 next 指针是用来【快速解树】的，从红黑树快速变成链表，通过遍历每个节点的 next 指针马上就可以恢复成一个链表，太妙了！！！！</span></span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">TreeNode</span>&lt;&gt;(p.hash, p.key, p.value, next);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Entry for Tree bins. Extends LinkedHashMap.Entry (which in turn</span></span><br><span class="line"><span class="comment"> * extends Node) so can be used as extension of either regular or</span></span><br><span class="line"><span class="comment"> * linked node.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="comment">// TreeNode 的结构，继承 LinkedHashMap.Entry&lt;K,V&gt;，最终继承了 Node</span></span><br><span class="line"><span class="comment">// 为什么不直接继承 Node？</span></span><br><span class="line"><span class="comment">// 因为 TreeNode 还需要继承 LinkedHashMap.Entry&lt;K,V&gt; 中的属性方便对 LinkedHashMap 操作。</span></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">class</span> <span class="title class_">TreeNode</span>&lt;K,V&gt; <span class="keyword">extends</span> <span class="title class_">LinkedHashMap</span>.Entry&lt;K,V&gt; &#123;</span><br><span class="line">    TreeNode&lt;K,V&gt; parent;  <span class="comment">// red-black tree links</span></span><br><span class="line">    TreeNode&lt;K,V&gt; left;</span><br><span class="line">    TreeNode&lt;K,V&gt; right;</span><br><span class="line">    TreeNode&lt;K,V&gt; prev;    <span class="comment">// needed to unlink next upon deletion</span></span><br><span class="line">    <span class="type">boolean</span> red;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 没有 next 指针</span></span><br><span class="line">    </span><br><span class="line">    TreeNode(<span class="type">int</span> hash, K key, V val, Node&lt;K,V&gt; next) &#123;</span><br><span class="line">        <span class="built_in">super</span>(hash, key, val, next);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// ...</span></span><br><span class="line">    </span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// LinkedHashMap.Entry&lt;K,V&gt;</span></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">Entry</span>&lt;K,V&gt; <span class="keyword">extends</span> <span class="title class_">HashMap</span>.Node&lt;K,V&gt; &#123;</span><br><span class="line">    Entry&lt;K,V&gt; before, after; <span class="comment">// 记录了前驱节点和后继节点</span></span><br><span class="line">    Entry(<span class="type">int</span> hash, K key, V value, Node&lt;K,V&gt; next) &#123;</span><br><span class="line">        <span class="built_in">super</span>(hash, key, value, next);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Forms tree of the nodes linked from this node.</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> root of tree</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="comment">// TODO</span></span><br><span class="line"><span class="comment">// 将双向链表树化为红黑树 - 简化版：双向链表转换二叉树，LeetCode 类似题目：https://leetcode.cn/problems/er-cha-sou-suo-shu-yu-shuang-xiang-lian-biao-lcof/</span></span><br><span class="line"><span class="keyword">final</span> <span class="keyword">void</span> <span class="title function_">treeify</span><span class="params">(Node&lt;K,V&gt;[] tab)</span> &#123;</span><br><span class="line">    TreeNode&lt;K,V&gt; root = <span class="literal">null</span>;</span><br><span class="line">    <span class="keyword">for</span> (TreeNode&lt;K,V&gt; x = <span class="built_in">this</span>, next; x != <span class="literal">null</span>; x = next) &#123;</span><br><span class="line">        next = (TreeNode&lt;K,V&gt;)x.next;</span><br><span class="line">        x.left = x.right = <span class="literal">null</span>;</span><br><span class="line">        <span class="keyword">if</span> (root == <span class="literal">null</span>) &#123;</span><br><span class="line">            x.parent = <span class="literal">null</span>;</span><br><span class="line">            x.red = <span class="literal">false</span>;</span><br><span class="line">            root = x;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="type">K</span> <span class="variable">k</span> <span class="operator">=</span> x.key;</span><br><span class="line">            <span class="type">int</span> <span class="variable">h</span> <span class="operator">=</span> x.hash;</span><br><span class="line">            Class&lt;?&gt; kc = <span class="literal">null</span>;</span><br><span class="line">            <span class="keyword">for</span> (TreeNode&lt;K,V&gt; p = root;;) &#123;</span><br><span class="line">                <span class="type">int</span> dir, ph;</span><br><span class="line">                <span class="type">K</span> <span class="variable">pk</span> <span class="operator">=</span> p.key;</span><br><span class="line">                <span class="keyword">if</span> ((ph = p.hash) &gt; h)</span><br><span class="line">                    dir = -<span class="number">1</span>;</span><br><span class="line">                <span class="keyword">else</span> <span class="keyword">if</span> (ph &lt; h)</span><br><span class="line">                    dir = <span class="number">1</span>;</span><br><span class="line">                <span class="keyword">else</span> <span class="keyword">if</span> ((kc == <span class="literal">null</span> &amp;&amp;</span><br><span class="line">                          (kc = comparableClassFor(k)) == <span class="literal">null</span>) ||</span><br><span class="line">                         (dir = compareComparables(kc, k, pk)) == <span class="number">0</span>)</span><br><span class="line">                    dir = tieBreakOrder(k, pk);</span><br><span class="line"></span><br><span class="line">                TreeNode&lt;K,V&gt; xp = p;</span><br><span class="line">                <span class="keyword">if</span> ((p = (dir &lt;= <span class="number">0</span>) ? p.left : p.right) == <span class="literal">null</span>) &#123;</span><br><span class="line">                    x.parent = xp;</span><br><span class="line">                    <span class="keyword">if</span> (dir &lt;= <span class="number">0</span>)</span><br><span class="line">                        xp.left = x;</span><br><span class="line">                    <span class="keyword">else</span></span><br><span class="line">                        xp.right = x;</span><br><span class="line">                    root = balanceInsertion(root, x);</span><br><span class="line">                    <span class="keyword">break</span>;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    moveRootToFront(tab, root);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="putAll-Map-lt-extends-K-extends-V-gt-m"><a href="#putAll-Map-lt-extends-K-extends-V-gt-m" class="headerlink" title="putAll(Map&lt;? extends K, ? extends V&gt; m)"></a>putAll(Map&lt;? extends K, ? extends V&gt; m)</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Copies all of the mappings from the specified map to this map.</span></span><br><span class="line"><span class="comment"> * These mappings will replace any mappings that this map had for</span></span><br><span class="line"><span class="comment"> * any of the keys currently in the specified map.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> m mappings to be stored in this map</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@throws</span> NullPointerException if the specified map is null</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="comment">// put 一个 map 到 map 中</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">putAll</span><span class="params">(Map&lt;? extends K, ? extends V&gt; m)</span> &#123;</span><br><span class="line">    <span class="comment">// 调用的就是 putMapEntries，上面已经分析过了</span></span><br><span class="line">    putMapEntries(m, <span class="literal">true</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="remove-Object-key"><a href="#remove-Object-key" class="headerlink" title="remove(Object key)"></a>remove(Object key)</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Removes the mapping for the specified key from this map if present.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span>  key key whose mapping is to be removed from the map</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> the previous value associated with &lt;tt&gt;key&lt;/tt&gt;, or</span></span><br><span class="line"><span class="comment"> *         &lt;tt&gt;null&lt;/tt&gt; if there was no mapping for &lt;tt&gt;key&lt;/tt&gt;.</span></span><br><span class="line"><span class="comment"> *         (A &lt;tt&gt;null&lt;/tt&gt; return can also indicate that the map</span></span><br><span class="line"><span class="comment"> *         previously associated &lt;tt&gt;null&lt;/tt&gt; with &lt;tt&gt;key&lt;/tt&gt;.)</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="comment">// 根据 key 删除一个节点</span></span><br><span class="line"><span class="keyword">public</span> V <span class="title function_">remove</span><span class="params">(Object key)</span> &#123;</span><br><span class="line">    Node&lt;K,V&gt; e;</span><br><span class="line">    <span class="keyword">return</span> (e = removeNode(hash(key), key, <span class="literal">null</span>, <span class="literal">false</span>, <span class="literal">true</span>)) == <span class="literal">null</span> ?</span><br><span class="line">        <span class="literal">null</span> : e.value;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Implements Map.remove and related methods</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> hash hash for key</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> key the key</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> value the value to match if matchValue, else ignored</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> matchValue if true only remove if value is equal</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> movable if false do not move other nodes while removing</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> the node, or null if none</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="comment">// 删除一个节点</span></span><br><span class="line"><span class="keyword">final</span> Node&lt;K,V&gt; <span class="title function_">removeNode</span><span class="params">(<span class="type">int</span> hash, Object key, Object value,</span></span><br><span class="line"><span class="params">                           <span class="type">boolean</span> matchValue, <span class="type">boolean</span> movable)</span> &#123;</span><br><span class="line">    Node&lt;K,V&gt;[] tab; Node&lt;K,V&gt; p; <span class="type">int</span> n, index;</span><br><span class="line">    <span class="keyword">if</span> ((tab = table) != <span class="literal">null</span> &amp;&amp; (n = tab.length) &gt; <span class="number">0</span> &amp;&amp; <span class="comment">// (tab = table) != null &amp;&amp; (n = tab.length) &gt; 0 表示 HashMap 不为空，且有元素</span></span><br><span class="line">        (p = tab[index = (n - <span class="number">1</span>) &amp; hash]) != <span class="literal">null</span>) &#123; <span class="comment">// 获取当前槽位上的头节点 p 且 p 不为 null</span></span><br><span class="line">        Node&lt;K,V&gt; node = <span class="literal">null</span>, e; K k; V v; <span class="comment">// node 就是最后要删除的节点</span></span><br><span class="line">        <span class="comment">// 说明头节点 p 就是要删除的节点</span></span><br><span class="line">        <span class="keyword">if</span> (p.hash == hash &amp;&amp;</span><br><span class="line">            ((k = p.key) == key || (key != <span class="literal">null</span> &amp;&amp; key.equals(k))))</span><br><span class="line">            node = p;</span><br><span class="line">        <span class="comment">// 如果不是头节点，继续判断，这里 p.next 既可以得到链表的下一个节点也可以得到红黑树的下一个节点，原因就是 TreeNode 是 Node 子类，同时我们也给 next 赋值了</span></span><br><span class="line">        <span class="keyword">else</span> <span class="keyword">if</span> ((e = p.next) != <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="comment">// 如果是树节点，则获取 TreeNode</span></span><br><span class="line">            <span class="keyword">if</span> (p <span class="keyword">instanceof</span> TreeNode)</span><br><span class="line">                node = ((TreeNode&lt;K,V&gt;)p).getTreeNode(hash, key);</span><br><span class="line">            <span class="comment">// 否则就是链表</span></span><br><span class="line">            <span class="keyword">else</span> &#123; </span><br><span class="line">                <span class="comment">// do while 遍历链表，如果 e 是待删除节点则赋值给 node，直接 break</span></span><br><span class="line">                <span class="keyword">do</span> &#123;</span><br><span class="line">                    <span class="keyword">if</span> (e.hash == hash &amp;&amp;</span><br><span class="line">                        ((k = e.key) == key ||</span><br><span class="line">                         (key != <span class="literal">null</span> &amp;&amp; key.equals(k)))) &#123;</span><br><span class="line">                        node = e;</span><br><span class="line">                        <span class="keyword">break</span>;</span><br><span class="line">                    &#125;</span><br><span class="line">                    p = e; <span class="comment">// p 最终指向待删除的节点 e 的上一个节点</span></span><br><span class="line">                &#125; <span class="keyword">while</span> ((e = e.next) != <span class="literal">null</span>);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        </span><br><span class="line">        <span class="comment">// ----- 真正的删除 node 节点</span></span><br><span class="line">        <span class="comment">// node 不为空，说明找到了 node，上面 remove() 方法传入的 matchValue = false</span></span><br><span class="line">        <span class="keyword">if</span> (node != <span class="literal">null</span> &amp;&amp; (!matchValue || (v = node.value) == value ||</span><br><span class="line">                             (value != <span class="literal">null</span> &amp;&amp; value.equals(v)))) &#123;</span><br><span class="line">            <span class="comment">// 如果 node 是树节点，则调用 removeTreeNode 删除树节点</span></span><br><span class="line">            <span class="keyword">if</span> (node <span class="keyword">instanceof</span> TreeNode)</span><br><span class="line">                ((TreeNode&lt;K,V&gt;)node).removeTreeNode(<span class="built_in">this</span>, tab, movable);</span><br><span class="line">            <span class="comment">// 否则如果 node 是槽位上的链表的头节点 p，则头节点替换为下一个节点</span></span><br><span class="line">            <span class="keyword">else</span> <span class="keyword">if</span> (node == p)</span><br><span class="line">                tab[index] = node.next;</span><br><span class="line">            <span class="comment">// 否则如果 node 不是链表头节点，则一步操作单链表删除 node</span></span><br><span class="line">            <span class="keyword">else</span></span><br><span class="line">                p.next = node.next;</span><br><span class="line">            ++modCount; <span class="comment">// 修改次数 + </span></span><br><span class="line">            --size; <span class="comment">// 元素个数 - 1</span></span><br><span class="line">            afterNodeRemoval(node); <span class="comment">// LinkedHashMap 的模板方法，对 HashMap 不起作用</span></span><br><span class="line">            <span class="keyword">return</span> node; <span class="comment">// 返回删除的值</span></span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> <span class="literal">null</span>; <span class="comment">// 不存在返回 null</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="containsValue-Object-value"><a href="#containsValue-Object-value" class="headerlink" title="containsValue(Object value)"></a>containsValue(Object value)</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Returns &lt;tt&gt;true&lt;/tt&gt; if this map maps one or more keys to the</span></span><br><span class="line"><span class="comment"> * specified value.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> value value whose presence in this map is to be tested</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> &lt;tt&gt;true&lt;/tt&gt; if this map maps one or more keys to the</span></span><br><span class="line"><span class="comment"> *         specified value</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">containsValue</span><span class="params">(Object value)</span> &#123;</span><br><span class="line">    Node&lt;K,V&gt;[] tab; V v;</span><br><span class="line">    <span class="keyword">if</span> ((tab = table) != <span class="literal">null</span> &amp;&amp; size &gt; <span class="number">0</span>) &#123; <span class="comment">// 保证 table 不为空，有元素</span></span><br><span class="line">        <span class="keyword">for</span> (<span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> <span class="number">0</span>; i &lt; tab.length; ++i) &#123; <span class="comment">// 遍历数组</span></span><br><span class="line">            <span class="keyword">for</span> (Node&lt;K,V&gt; e = tab[i]; e != <span class="literal">null</span>; e = e.next) &#123; <span class="comment">// 遍历每个槽位上的节点（可能是链表、可能是树）都可以通过 next 指针遍历</span></span><br><span class="line">                <span class="keyword">if</span> ((v = e.value) == value ||</span><br><span class="line">                    (value != <span class="literal">null</span> &amp;&amp; value.equals(v))) <span class="comment">// 如果值相等返回 true</span></span><br><span class="line">                    <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="keySet-和-values"><a href="#keySet-和-values" class="headerlink" title="keySet() 和 values()"></a>keySet() 和 values()</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Returns a &#123;<span class="doctag">@link</span> Set&#125; view of the keys contained in this map.</span></span><br><span class="line"><span class="comment"> * The set is backed by the map, so changes to the map are</span></span><br><span class="line"><span class="comment"> * reflected in the set, and vice-versa.  If the map is modified</span></span><br><span class="line"><span class="comment"> * while an iteration over the set is in progress (except through</span></span><br><span class="line"><span class="comment"> * the iterator&#x27;s own &lt;tt&gt;remove&lt;/tt&gt; operation), the results of</span></span><br><span class="line"><span class="comment"> * the iteration are undefined.  The set supports element removal,</span></span><br><span class="line"><span class="comment"> * which removes the corresponding mapping from the map, via the</span></span><br><span class="line"><span class="comment"> * &lt;tt&gt;Iterator.remove&lt;/tt&gt;, &lt;tt&gt;Set.remove&lt;/tt&gt;,</span></span><br><span class="line"><span class="comment"> * &lt;tt&gt;removeAll&lt;/tt&gt;, &lt;tt&gt;retainAll&lt;/tt&gt;, and &lt;tt&gt;clear&lt;/tt&gt;</span></span><br><span class="line"><span class="comment"> * operations.  It does not support the &lt;tt&gt;add&lt;/tt&gt; or &lt;tt&gt;addAll&lt;/tt&gt;</span></span><br><span class="line"><span class="comment"> * operations.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> a set view of the keys contained in this map</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="comment">// 获取 HashMap 的所有 key，是通过继承类 AbstractMap 的属性赋值的</span></span><br><span class="line"><span class="comment">// 这里的 key 都是指向 HashMap 的一个引用，而不存储真正的值，所以当 HashMap 中删除了某个键值对，keySet() 也就没有了这个 key</span></span><br><span class="line"><span class="comment">// 根据注释可以看到不支持 add() 和 addAll()，因为 KeySet 没有实现 add() 和 addAll() 调用父类的实现就是抛出异常</span></span><br><span class="line"><span class="keyword">public</span> Set&lt;K&gt; <span class="title function_">keySet</span><span class="params">()</span> &#123;</span><br><span class="line">    Set&lt;K&gt; ks = keySet;</span><br><span class="line">    <span class="keyword">if</span> (ks == <span class="literal">null</span>) &#123;</span><br><span class="line">        ks = <span class="keyword">new</span> <span class="title class_">KeySet</span>(); <span class="comment">// KeySet 是内部类，有 remove() 方法</span></span><br><span class="line">        keySet = ks;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> ks;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Returns a &#123;<span class="doctag">@link</span> Collection&#125; view of the values contained in this map.</span></span><br><span class="line"><span class="comment"> * The collection is backed by the map, so changes to the map are</span></span><br><span class="line"><span class="comment"> * reflected in the collection, and vice-versa.  If the map is</span></span><br><span class="line"><span class="comment"> * modified while an iteration over the collection is in progress</span></span><br><span class="line"><span class="comment"> * (except through the iterator&#x27;s own &lt;tt&gt;remove&lt;/tt&gt; operation),</span></span><br><span class="line"><span class="comment"> * the results of the iteration are undefined.  The collection</span></span><br><span class="line"><span class="comment"> * supports element removal, which removes the corresponding</span></span><br><span class="line"><span class="comment"> * mapping from the map, via the &lt;tt&gt;Iterator.remove&lt;/tt&gt;,</span></span><br><span class="line"><span class="comment"> * &lt;tt&gt;Collection.remove&lt;/tt&gt;, &lt;tt&gt;removeAll&lt;/tt&gt;,</span></span><br><span class="line"><span class="comment"> * &lt;tt&gt;retainAll&lt;/tt&gt; and &lt;tt&gt;clear&lt;/tt&gt; operations.  It does not</span></span><br><span class="line"><span class="comment"> * support the &lt;tt&gt;add&lt;/tt&gt; or &lt;tt&gt;addAll&lt;/tt&gt; operations.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> a view of the values contained in this map</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> Collection&lt;V&gt; <span class="title function_">values</span><span class="params">()</span> &#123;</span><br><span class="line">    Collection&lt;V&gt; vs = values;</span><br><span class="line">    <span class="keyword">if</span> (vs == <span class="literal">null</span>) &#123;</span><br><span class="line">        vs = <span class="keyword">new</span> <span class="title class_">Values</span>(); <span class="comment">// Values 是内部类，没有 remove() 方法，所以不能删除值，只能删除 key</span></span><br><span class="line">        values = vs;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> vs;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// AbstractMap&lt;K,V&gt;</span></span><br><span class="line"><span class="keyword">transient</span> Set&lt;K&gt;        keySet;</span><br><span class="line"><span class="keyword">transient</span> Collection&lt;V&gt; values;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h2 id="entrySet"><a href="#entrySet" class="headerlink" title="entrySet()"></a>entrySet()</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Returns a &#123;<span class="doctag">@link</span> Set&#125; view of the mappings contained in this map.</span></span><br><span class="line"><span class="comment"> * The set is backed by the map, so changes to the map are</span></span><br><span class="line"><span class="comment"> * reflected in the set, and vice-versa.  If the map is modified</span></span><br><span class="line"><span class="comment"> * while an iteration over the set is in progress (except through</span></span><br><span class="line"><span class="comment"> * the iterator&#x27;s own &lt;tt&gt;remove&lt;/tt&gt; operation, or through the</span></span><br><span class="line"><span class="comment"> * &lt;tt&gt;setValue&lt;/tt&gt; operation on a map entry returned by the</span></span><br><span class="line"><span class="comment"> * iterator) the results of the iteration are undefined.  The set</span></span><br><span class="line"><span class="comment"> * supports element removal, which removes the corresponding</span></span><br><span class="line"><span class="comment"> * mapping from the map, via the &lt;tt&gt;Iterator.remove&lt;/tt&gt;,</span></span><br><span class="line"><span class="comment"> * &lt;tt&gt;Set.remove&lt;/tt&gt;, &lt;tt&gt;removeAll&lt;/tt&gt;, &lt;tt&gt;retainAll&lt;/tt&gt; and</span></span><br><span class="line"><span class="comment"> * &lt;tt&gt;clear&lt;/tt&gt; operations.  It does not support the</span></span><br><span class="line"><span class="comment"> * &lt;tt&gt;add&lt;/tt&gt; or &lt;tt&gt;addAll&lt;/tt&gt; operations.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> a set view of the mappings contained in this map</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="comment">// 获取 HashMap 的键值对</span></span><br><span class="line"><span class="keyword">public</span> Set&lt;Map.Entry&lt;K,V&gt;&gt; entrySet() &#123;</span><br><span class="line">    Set&lt;Map.Entry&lt;K,V&gt;&gt; es;</span><br><span class="line">    <span class="keyword">return</span> (es = entrySet) == <span class="literal">null</span> ? (entrySet = <span class="keyword">new</span> <span class="title class_">EntrySet</span>()) : es;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// HashMap</span></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Holds cached entrySet(). Note that AbstractMap fields are used</span></span><br><span class="line"><span class="comment"> * for keySet() and values().</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">transient</span> Set&lt;Map.Entry&lt;K,V&gt;&gt; entrySet;</span><br><span class="line"></span><br><span class="line"><span class="comment">// EntrySet 是内部类</span></span><br></pre></td></tr></table></figure><h2 id="remove-Object-key-Object-value"><a href="#remove-Object-key-Object-value" class="headerlink" title="remove(Object key, Object value)"></a>remove(Object key, Object value)</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 只有 key 和 value 都匹配才去删除节点 </span></span><br><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">remove</span><span class="params">(Object key, Object value)</span> &#123;</span><br><span class="line">    <span class="comment">// 第一个 true 表示 matchValue = true，调用 removeNode() 的时候会判断</span></span><br><span class="line">    <span class="keyword">return</span> removeNode(hash(key), key, value, <span class="literal">true</span>, <span class="literal">true</span>) != <span class="literal">null</span>; </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="replace"><a href="#replace" class="headerlink" title="replace()"></a>replace()</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">replace</span><span class="params">(K key, V oldValue, V newValue)</span> &#123;</span><br><span class="line">    Node&lt;K,V&gt; e; V v;</span><br><span class="line">    <span class="keyword">if</span> ((e = getNode(hash(key), key)) != <span class="literal">null</span> &amp;&amp;</span><br><span class="line">        ((v = e.value) == oldValue || (v != <span class="literal">null</span> &amp;&amp; v.equals(oldValue)))) &#123; <span class="comment">// getNode 获取匹配的节点，匹配就修改返回 true，否则返回 false</span></span><br><span class="line">        e.value = newValue;</span><br><span class="line">        afterNodeAccess(e);</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="keyword">public</span> V <span class="title function_">replace</span><span class="params">(K key, V value)</span> &#123;</span><br><span class="line">    Node&lt;K,V&gt; e;</span><br><span class="line">    <span class="keyword">if</span> ((e = getNode(hash(key), key)) != <span class="literal">null</span>) &#123; <span class="comment">// getNode 获取匹配的节点，匹配就修改返回 true，否则返回 false</span></span><br><span class="line">        <span class="type">V</span> <span class="variable">oldValue</span> <span class="operator">=</span> e.value;</span><br><span class="line">        e.value = value;</span><br><span class="line">        afterNodeAccess(e);</span><br><span class="line">        <span class="keyword">return</span> oldValue;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="clone-浅克隆"><a href="#clone-浅克隆" class="headerlink" title="clone() 浅克隆"></a>clone() 浅克隆</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Returns a shallow copy of this &lt;tt&gt;HashMap&lt;/tt&gt; instance: the keys and</span></span><br><span class="line"><span class="comment"> * values themselves are not cloned.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> a shallow copy of this map</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@SuppressWarnings(&quot;unchecked&quot;)</span></span><br><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="keyword">public</span> Object <span class="title function_">clone</span><span class="params">()</span> &#123; <span class="comment">// 调用方式 B = A.clone() 克隆 A 赋值给 B</span></span><br><span class="line">    HashMap&lt;K,V&gt; result;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        result = (HashMap&lt;K,V&gt;)<span class="built_in">super</span>.clone(); <span class="comment">// 调用的就是 Object 的 clone()</span></span><br><span class="line">    &#125; <span class="keyword">catch</span> (CloneNotSupportedException e) &#123;</span><br><span class="line">        <span class="comment">// this shouldn&#x27;t happen, since we are Cloneable</span></span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">InternalError</span>(e);</span><br><span class="line">    &#125;</span><br><span class="line">    result.reinitialize(); <span class="comment">// result 重新初始化</span></span><br><span class="line">    result.putMapEntries(<span class="built_in">this</span>, <span class="literal">false</span>); <span class="comment">// 将 A 的键值对 put 到 result 里</span></span><br><span class="line">    <span class="keyword">return</span> result;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="loadFactor-和-capacity-获取两个属性值"><a href="#loadFactor-和-capacity-获取两个属性值" class="headerlink" title="loadFactor() 和 capacity() 获取两个属性值"></a>loadFactor() 和 capacity() 获取两个属性值</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// These methods are also used when serializing HashSets</span></span><br><span class="line"><span class="keyword">final</span> <span class="type">float</span> <span class="title function_">loadFactor</span><span class="params">()</span> &#123; <span class="keyword">return</span> loadFactor; &#125;</span><br><span class="line"><span class="keyword">final</span> <span class="type">int</span> <span class="title function_">capacity</span><span class="params">()</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> (table != <span class="literal">null</span>) ? table.length : <span class="comment">// table 不为空容量就是 length</span></span><br><span class="line">        (threshold &gt; <span class="number">0</span>) ? threshold :</span><br><span class="line">        DEFAULT_INITIAL_CAPACITY;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="writeObject-序列化和-readOject-反序列化"><a href="#writeObject-序列化和-readOject-反序列化" class="headerlink" title="writeObject() 序列化和 readOject() 反序列化"></a>writeObject() 序列化和 readOject() 反序列化</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Save the state of the &lt;tt&gt;HashMap&lt;/tt&gt; instance to a stream (i.e.,</span></span><br><span class="line"><span class="comment"> * serialize it).</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@serialData</span> The &lt;i&gt;capacity&lt;/i&gt; of the HashMap (the length of the</span></span><br><span class="line"><span class="comment"> *             bucket array) is emitted (int), followed by the</span></span><br><span class="line"><span class="comment"> *             &lt;i&gt;size&lt;/i&gt; (an int, the number of key-value</span></span><br><span class="line"><span class="comment"> *             mappings), followed by the key (Object) and value (Object)</span></span><br><span class="line"><span class="comment"> *             for each key-value mapping.  The key-value mappings are</span></span><br><span class="line"><span class="comment"> *             emitted in no particular order.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="comment">// 序列化</span></span><br><span class="line"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title function_">writeObject</span><span class="params">(java.io.ObjectOutputStream s)</span></span><br><span class="line">    <span class="keyword">throws</span> IOException &#123;</span><br><span class="line">    <span class="type">int</span> <span class="variable">buckets</span> <span class="operator">=</span> capacity(); <span class="comment">// 获取容量</span></span><br><span class="line">    <span class="comment">// Write out the threshold, loadfactor, and any hidden stuff</span></span><br><span class="line">    s.defaultWriteObject(); <span class="comment">// 设置 输出流</span></span><br><span class="line">    s.writeInt(buckets); <span class="comment">// 先写容量</span></span><br><span class="line">    s.writeInt(size); <span class="comment">// 再写大小</span></span><br><span class="line">    internalWriteEntries(s); <span class="comment">// 再遍历 HashMap 一个一个的序列化键值对，空位置不处理</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// Called only from writeObject, to ensure compatible ordering.</span></span><br><span class="line"><span class="keyword">void</span> <span class="title function_">internalWriteEntries</span><span class="params">(java.io.ObjectOutputStream s)</span> <span class="keyword">throws</span> IOException &#123;</span><br><span class="line">    Node&lt;K,V&gt;[] tab;</span><br><span class="line">    <span class="keyword">if</span> (size &gt; <span class="number">0</span> &amp;&amp; (tab = table) != <span class="literal">null</span>) &#123; <span class="comment">// table 不为空</span></span><br><span class="line">        <span class="keyword">for</span> (<span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> <span class="number">0</span>; i &lt; tab.length; ++i) &#123; <span class="comment">// 遍历每个槽位</span></span><br><span class="line">            <span class="keyword">for</span> (Node&lt;K,V&gt; e = tab[i]; e != <span class="literal">null</span>; e =  e.next) &#123; <span class="comment">// 遍历每个槽位上的键值对</span></span><br><span class="line">                s.writeObject(e.key); <span class="comment">// 写 key</span></span><br><span class="line">                s.writeObject(e.value); <span class="comment">// 写 value</span></span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Reconstitute the &#123;<span class="doctag">@code</span> HashMap&#125; instance from a stream (i.e.,</span></span><br><span class="line"><span class="comment"> * deserialize it).</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="comment">// 反序列化</span></span><br><span class="line"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title function_">readObject</span><span class="params">(java.io.ObjectInputStream s)</span></span><br><span class="line">    <span class="keyword">throws</span> IOException, ClassNotFoundException &#123;</span><br><span class="line">    <span class="comment">// Read in the threshold (ignored), loadfactor, and any hidden stuff</span></span><br><span class="line">    s.defaultReadObject(); <span class="comment">// 设置输入流</span></span><br><span class="line">    reinitialize(); <span class="comment">// 重新初始化</span></span><br><span class="line">    <span class="keyword">if</span> (loadFactor &lt;= <span class="number">0</span> || Float.isNaN(loadFactor))</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">InvalidObjectException</span>(<span class="string">&quot;Illegal load factor: &quot;</span> +</span><br><span class="line">                                         loadFactor);</span><br><span class="line">    <span class="comment">// --- 读取 容量</span></span><br><span class="line">    s.readInt();                <span class="comment">// Read and ignore number of buckets</span></span><br><span class="line">    <span class="comment">// -- 读取元素个数</span></span><br><span class="line">    <span class="type">int</span> <span class="variable">mappings</span> <span class="operator">=</span> s.readInt(); <span class="comment">// Read number of mappings (size)</span></span><br><span class="line">    <span class="keyword">if</span> (mappings &lt; <span class="number">0</span>) <span class="comment">// 没元素抛异常</span></span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">InvalidObjectException</span>(<span class="string">&quot;Illegal mappings count: &quot;</span> +</span><br><span class="line">                                         mappings);</span><br><span class="line">    <span class="keyword">else</span> <span class="keyword">if</span> (mappings &gt; <span class="number">0</span>) &#123; <span class="comment">// (if zero, use defaults)</span></span><br><span class="line">        <span class="comment">// Size the table using given load factor only if within</span></span><br><span class="line">        <span class="comment">// range of 0.25...4.0</span></span><br><span class="line">        <span class="type">float</span> <span class="variable">lf</span> <span class="operator">=</span> Math.min(Math.max(<span class="number">0.25f</span>, loadFactor), <span class="number">4.0f</span>);</span><br><span class="line">        <span class="type">float</span> <span class="variable">fc</span> <span class="operator">=</span> (<span class="type">float</span>)mappings / lf + <span class="number">1.0f</span>;</span><br><span class="line">        <span class="comment">// 计算容量</span></span><br><span class="line">        <span class="type">int</span> <span class="variable">cap</span> <span class="operator">=</span> ((fc &lt; DEFAULT_INITIAL_CAPACITY) ?</span><br><span class="line">                   DEFAULT_INITIAL_CAPACITY :</span><br><span class="line">                   (fc &gt;= MAXIMUM_CAPACITY) ?</span><br><span class="line">                   MAXIMUM_CAPACITY :</span><br><span class="line">                   tableSizeFor((<span class="type">int</span>)fc));</span><br><span class="line">        <span class="type">float</span> <span class="variable">ft</span> <span class="operator">=</span> (<span class="type">float</span>)cap * lf;</span><br><span class="line">        <span class="comment">// 计算 threshold</span></span><br><span class="line">        threshold = ((cap &lt; MAXIMUM_CAPACITY &amp;&amp; ft &lt; MAXIMUM_CAPACITY) ?</span><br><span class="line">                     (<span class="type">int</span>)ft : Integer.MAX_VALUE);</span><br><span class="line"></span><br><span class="line">        <span class="comment">// Check Map.Entry[].class since it&#x27;s the nearest public type to</span></span><br><span class="line">        <span class="comment">// what we&#x27;re actually creating.</span></span><br><span class="line">        SharedSecrets.getJavaOISAccess().checkArray(s, Map.Entry[].class, cap);</span><br><span class="line">        <span class="meta">@SuppressWarnings(&#123;&quot;rawtypes&quot;,&quot;unchecked&quot;&#125;)</span></span><br><span class="line">        Node&lt;K,V&gt;[] tab = (Node&lt;K,V&gt;[])<span class="keyword">new</span> <span class="title class_">Node</span>[cap];</span><br><span class="line">        table = tab;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// Read the keys and values, and put the mappings in the HashMap</span></span><br><span class="line">        <span class="comment">// 遍历 size 次，每次读取一个 key 和 value，put 到 table 中</span></span><br><span class="line">        <span class="keyword">for</span> (<span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> <span class="number">0</span>; i &lt; mappings; i++) &#123;</span><br><span class="line">            <span class="meta">@SuppressWarnings(&quot;unchecked&quot;)</span></span><br><span class="line">                <span class="type">K</span> <span class="variable">key</span> <span class="operator">=</span> (K) s.readObject();</span><br><span class="line">            <span class="meta">@SuppressWarnings(&quot;unchecked&quot;)</span></span><br><span class="line">                <span class="type">V</span> <span class="variable">value</span> <span class="operator">=</span> (V) s.readObject();</span><br><span class="line">            putVal(hash(key), key, value, <span class="literal">false</span>, <span class="literal">false</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">&lt;h2 id=&quot;HashMap-类属性&quot;&gt;&lt;a href=&quot;#HashMap-类属性&quot; class=&quot;headerlink&quot; title=&quot;HashMap 类属性&quot;&gt;&lt;/a&gt;HashMap 类属性&lt;/h2&gt;&lt;p&gt;HashMap 继承于 AbstractMap，实现了 Map、Cloneable、java.io.Serializable 接口，是非常常用的一个集合类，同时在 JDK 1.7 和 JDK 1.8 版本的底层实现上也有很大区别。&lt;/p&gt;</summary>
    
    
    
    <category term="Java" scheme="https://tonngw.com/categories/Java/"/>
    
    <category term="Java 集合" scheme="https://tonngw.com/categories/Java/Java-%E9%9B%86%E5%90%88/"/>
    
    
    <category term="Java" scheme="https://tonngw.com/tags/Java/"/>
    
    <category term="Java 集合" scheme="https://tonngw.com/tags/Java-%E9%9B%86%E5%90%88/"/>
    
    <category term="源码" scheme="https://tonngw.com/tags/%E6%BA%90%E7%A0%81/"/>
    
    <category term="HashMap" scheme="https://tonngw.com/tags/HashMap/"/>
    
  </entry>
  
  <entry>
    <title>ArrayList 源码精读笔记</title>
    <link href="https://tonngw.com/2022/07/26/ArrayList%20%E6%BA%90%E7%A0%81%E7%B2%BE%E8%AF%BB/"/>
    <id>https://tonngw.com/2022/07/26/ArrayList%20%E6%BA%90%E7%A0%81%E7%B2%BE%E8%AF%BB/</id>
    <published>2022-07-26T13:09:32.074Z</published>
    <updated>2022-07-26T13:28:20.687Z</updated>
    
    <content type="html"><![CDATA[<h2 id="ArrayList-类属性"><a href="#ArrayList-类属性" class="headerlink" title="ArrayList 类属性"></a>ArrayList 类属性</h2><p>ArrayList 实现了 RandomAccess 接口，RandomAccess 接口没有内容只是一个标记，对于实现了 RandomAccess 接口的类支持通过索引&#x2F;下标访问。</p><p>对于实现了 RandomAccess 接口的类使用 for 循环遍历效率高，没有实现的类尽量使用迭代器遍历</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> java.util;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.function.Consumer;</span><br><span class="line"><span class="keyword">import</span> java.util.function.Predicate;</span><br><span class="line"><span class="keyword">import</span> java.util.function.UnaryOperator;</span><br><span class="line"><span class="keyword">import</span> sun.misc.SharedSecrets;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Resizable-array implementation of the &lt;tt&gt;List&lt;/tt&gt; interface.  Implements</span></span><br><span class="line"><span class="comment"> * all optional list operations, and permits all elements, including</span></span><br><span class="line"><span class="comment"> * &lt;tt&gt;null&lt;/tt&gt;.  In addition to implementing the &lt;tt&gt;List&lt;/tt&gt; interface,</span></span><br><span class="line"><span class="comment"> * this class provides methods to manipulate the size of the array that is</span></span><br><span class="line"><span class="comment"> * used internally to store the list.  (This class is roughly equivalent to</span></span><br><span class="line"><span class="comment"> * &lt;tt&gt;Vector&lt;/tt&gt;, except that it is unsynchronized.)</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * &lt;p&gt;The &lt;tt&gt;size&lt;/tt&gt;, &lt;tt&gt;isEmpty&lt;/tt&gt;, &lt;tt&gt;get&lt;/tt&gt;, &lt;tt&gt;set&lt;/tt&gt;,</span></span><br><span class="line"><span class="comment"> * &lt;tt&gt;iterator&lt;/tt&gt;, and &lt;tt&gt;listIterator&lt;/tt&gt; operations run in constant</span></span><br><span class="line"><span class="comment"> * time.  The &lt;tt&gt;add&lt;/tt&gt; operation runs in &lt;i&gt;amortized constant time&lt;/i&gt;,</span></span><br><span class="line"><span class="comment"> * that is, adding n elements requires O(n) time.  All of the other operations</span></span><br><span class="line"><span class="comment"> * run in linear time (roughly speaking).  The constant factor is low compared</span></span><br><span class="line"><span class="comment"> * to that for the &lt;tt&gt;LinkedList&lt;/tt&gt; implementation.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * &lt;p&gt;Each &lt;tt&gt;ArrayList&lt;/tt&gt; instance has a &lt;i&gt;capacity&lt;/i&gt;.  The capacity is</span></span><br><span class="line"><span class="comment"> * the size of the array used to store the elements in the list.  It is always</span></span><br><span class="line"><span class="comment"> * at least as large as the list size.  As elements are added to an ArrayList,</span></span><br><span class="line"><span class="comment"> * its capacity grows automatically.  The details of the growth policy are not</span></span><br><span class="line"><span class="comment"> * specified beyond the fact that adding an element has constant amortized</span></span><br><span class="line"><span class="comment"> * time cost.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * &lt;p&gt;An application can increase the capacity of an &lt;tt&gt;ArrayList&lt;/tt&gt; instance</span></span><br><span class="line"><span class="comment"> * before adding a large number of elements using the &lt;tt&gt;ensureCapacity&lt;/tt&gt;</span></span><br><span class="line"><span class="comment"> * operation.  This may reduce the amount of incremental reallocation.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * &lt;p&gt;&lt;strong&gt;Note that this implementation is not synchronized.&lt;/strong&gt;</span></span><br><span class="line"><span class="comment"> * If multiple threads access an &lt;tt&gt;ArrayList&lt;/tt&gt; instance concurrently,</span></span><br><span class="line"><span class="comment"> * and at least one of the threads modifies the list structurally, it</span></span><br><span class="line"><span class="comment"> * &lt;i&gt;must&lt;/i&gt; be synchronized externally.  (A structural modification is</span></span><br><span class="line"><span class="comment"> * any operation that adds or deletes one or more elements, or explicitly</span></span><br><span class="line"><span class="comment"> * resizes the backing array; merely setting the value of an element is not</span></span><br><span class="line"><span class="comment"> * a structural modification.)  This is typically accomplished by</span></span><br><span class="line"><span class="comment"> * synchronizing on some object that naturally encapsulates the list.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * If no such object exists, the list should be &quot;wrapped&quot; using the</span></span><br><span class="line"><span class="comment"> * &#123;<span class="doctag">@link</span> Collections#synchronizedList Collections.synchronizedList&#125;</span></span><br><span class="line"><span class="comment"> * method.  This is best done at creation time, to prevent accidental</span></span><br><span class="line"><span class="comment"> * unsynchronized access to the list:&lt;pre&gt;</span></span><br><span class="line"><span class="comment"> *   List list = Collections.synchronizedList(new ArrayList(...));&lt;/pre&gt;</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * &lt;p&gt;&lt;a name=&quot;fail-fast&quot;&gt;</span></span><br><span class="line"><span class="comment"> * The iterators returned by this class&#x27;s &#123;<span class="doctag">@link</span> #iterator() iterator&#125; and</span></span><br><span class="line"><span class="comment"> * &#123;<span class="doctag">@link</span> #listIterator(int) listIterator&#125; methods are &lt;em&gt;fail-fast&lt;/em&gt;:&lt;/a&gt;</span></span><br><span class="line"><span class="comment"> * if the list is structurally modified at any time after the iterator is</span></span><br><span class="line"><span class="comment"> * created, in any way except through the iterator&#x27;s own</span></span><br><span class="line"><span class="comment"> * &#123;<span class="doctag">@link</span> ListIterator#remove() remove&#125; or</span></span><br><span class="line"><span class="comment"> * &#123;<span class="doctag">@link</span> ListIterator#add(Object) add&#125; methods, the iterator will throw a</span></span><br><span class="line"><span class="comment"> * &#123;<span class="doctag">@link</span> ConcurrentModificationException&#125;.  Thus, in the face of</span></span><br><span class="line"><span class="comment"> * concurrent modification, the iterator fails quickly and cleanly, rather</span></span><br><span class="line"><span class="comment"> * than risking arbitrary, non-deterministic behavior at an undetermined</span></span><br><span class="line"><span class="comment"> * time in the future.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * &lt;p&gt;Note that the fail-fast behavior of an iterator cannot be guaranteed</span></span><br><span class="line"><span class="comment"> * as it is, generally speaking, impossible to make any hard guarantees in the</span></span><br><span class="line"><span class="comment"> * presence of unsynchronized concurrent modification.  Fail-fast iterators</span></span><br><span class="line"><span class="comment"> * throw &#123;<span class="doctag">@code</span> ConcurrentModificationException&#125; on a best-effort basis.</span></span><br><span class="line"><span class="comment"> * Therefore, it would be wrong to write a program that depended on this</span></span><br><span class="line"><span class="comment"> * exception for its correctness:  &lt;i&gt;the fail-fast behavior of iterators</span></span><br><span class="line"><span class="comment"> * should be used only to detect bugs.&lt;/i&gt;</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * &lt;p&gt;This class is a member of the</span></span><br><span class="line"><span class="comment"> * &lt;a href=&quot;&#123;<span class="doctag">@docRoot</span>&#125;/../technotes/guides/collections/index.html&quot;&gt;</span></span><br><span class="line"><span class="comment"> * Java Collections Framework&lt;/a&gt;.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span>  Josh Bloch</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span>  Neal Gafter</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@see</span>     Collection</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@see</span>     List</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@see</span>     LinkedList</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@see</span>     Vector</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@since</span>   1.2</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">ArrayList</span>&lt;E&gt; <span class="keyword">extends</span> <span class="title class_">AbstractList</span>&lt;E&gt;</span><br><span class="line">        <span class="keyword">implements</span> <span class="title class_">List</span>&lt;E&gt;, RandomAccess, Cloneable, java.io.Serializable</span><br><span class="line">&#123; <span class="comment">// 实现了 RandomAccess 接口支持随机访问，实现了 Cloneable 接口，是浅克隆的，实现了序列化接口 Serializable</span></span><br><span class="line">    <span class="comment">// 每次用于网络传输的类都需要生成了随机序列化，是书写规范，如果不写其实也会自动加上</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">long</span> <span class="variable">serialVersionUID</span> <span class="operator">=</span> <span class="number">8683452581122892189L</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * Default initial capacity.</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">int</span> <span class="variable">DEFAULT_CAPACITY</span> <span class="operator">=</span> <span class="number">10</span>; <span class="comment">// 默认容量</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * Shared empty array instance used for empty instances.</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> Object[] EMPTY_ELEMENTDATA = &#123;&#125;; <span class="comment">// 初始化空数组</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * Shared empty array instance used for default sized empty instances. We</span></span><br><span class="line"><span class="comment">     * distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when</span></span><br><span class="line"><span class="comment">     * first element is added.</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = &#123;&#125;; <span class="comment">// 和 EMPTY_ELEMENTDATA 做区分</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * The array buffer into which the elements of the ArrayList are stored.</span></span><br><span class="line"><span class="comment">     * The capacity of the ArrayList is the length of this array buffer. Any</span></span><br><span class="line"><span class="comment">     * empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA</span></span><br><span class="line"><span class="comment">     * will be expanded to DEFAULT_CAPACITY when the first element is added.</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="comment">// 真正存放数据的数组，transient 防止进行序列化，既然元素不支持序列化，那么类上为什么又实现了 Serilizable 接口呢</span></span><br><span class="line">    <span class="comment">// 这里是自己重写了序列化方法，节省了 50% 序列化的空间</span></span><br><span class="line">    <span class="keyword">transient</span> Object[] elementData; <span class="comment">// non-private to simplify nested class access</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * The size of the ArrayList (the number of elements it contains).</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@serial</span></span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="comment">// ArrayList 中包含的元素个数</span></span><br><span class="line">    <span class="keyword">private</span> <span class="type">int</span> size;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * Constructs an empty list with the specified initial capacity.</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span>  initialCapacity  the initial capacity of the list</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@throws</span> IllegalArgumentException if the specified initial capacity</span></span><br><span class="line"><span class="comment">     *         is negative</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="comment">// 带初始容量的构造器</span></span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">ArrayList</span><span class="params">(<span class="type">int</span> initialCapacity)</span> &#123;</span><br><span class="line">        <span class="keyword">if</span> (initialCapacity &gt; <span class="number">0</span>) &#123;</span><br><span class="line">            <span class="built_in">this</span>.elementData = <span class="keyword">new</span> <span class="title class_">Object</span>[initialCapacity];</span><br><span class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span> (initialCapacity == <span class="number">0</span>) &#123;</span><br><span class="line">            <span class="built_in">this</span>.elementData = EMPTY_ELEMENTDATA;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">IllegalArgumentException</span>(<span class="string">&quot;Illegal Capacity: &quot;</span>+</span><br><span class="line">                                               initialCapacity);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * Constructs an empty list with an initial capacity of ten.</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="comment">// 空参构造期</span></span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">ArrayList</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// ...</span></span><br><span class="line">    </span><br><span class="line">    </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="add-E-e-以及扩容机制"><a href="#add-E-e-以及扩容机制" class="headerlink" title="add(E e) 以及扩容机制"></a>add(E e) 以及扩容机制</h2><p>当我们初始化一个容量为 0 的 ArrayList 的容量 <code>ArrayList&lt;Object&gt; list = new ArrayList&lt;&gt;(0);</code></p><p>如果往集合中添加 10 个元素，则会扩容 7 次。这样做的效率非常低</p><p>所以如果我们知道需要多大的容量，则尽量在初始化的时候指定具体的容量，否则可以使用默认构造器，<strong>避免使用 0 参数</strong>。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">List&lt;Object&gt; list = <span class="keyword">new</span> <span class="title class_">ArrayList</span>&lt;&gt;(<span class="number">0</span>);</span><br><span class="line">list.add(<span class="string">&quot;a&quot;</span>); <span class="comment">// 第 1 次 add</span></span><br><span class="line">list.add(<span class="string">&quot;b&quot;</span>); list.add(<span class="string">&quot;c&quot;</span>); list.add(<span class="string">&quot;d&quot;</span>); list.add(<span class="string">&quot;e&quot;</span>); </span><br><span class="line">list.add(<span class="string">&quot;f&quot;</span>); list.add(<span class="string">&quot;g&quot;</span>); list.add(<span class="string">&quot;h&quot;</span>);list.add(<span class="string">&quot;i&quot;</span>);</span><br><span class="line">list.add(<span class="string">&quot;j&quot;</span>); <span class="comment">// 第 10 次 add</span></span><br></pre></td></tr></table></figure><p>下面时执行流程：</p><ol start="0"><li>执行带参数构造器，创建 ArrayList 对象</li></ol><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="title function_">ArrayList</span><span class="params">(<span class="type">int</span> initialCapacity)</span> &#123;</span><br><span class="line">    <span class="keyword">if</span> (initialCapacity &gt; <span class="number">0</span>) &#123; <span class="comment">// 如果初始容量大于 0，则直接创建一个 initialCapacity 的 Object 数组赋值给 elementData</span></span><br><span class="line">        <span class="built_in">this</span>.elementData = <span class="keyword">new</span> <span class="title class_">Object</span>[initialCapacity];</span><br><span class="line">    &#125; <span class="keyword">else</span> <span class="keyword">if</span> (initialCapacity == <span class="number">0</span>) &#123; <span class="comment">// 如果初始容量为 0 走这里，将 EMPTY_ELEMENTDATA 赋值给 elementData</span></span><br><span class="line">        <span class="built_in">this</span>.elementData = EMPTY_ELEMENTDATA;</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">IllegalArgumentException</span>(<span class="string">&quot;Illegal Capacity: &quot;</span>+</span><br><span class="line">                                           initialCapacity);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ol><li>首先执行第一步 <code>add(E e)</code></li></ol><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Appends the specified element to the end of this list.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> e element to be appended to this list</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> &lt;tt&gt;true&lt;/tt&gt; (as specified by &#123;<span class="doctag">@link</span> Collection#add&#125;)</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">add</span><span class="params">(E e)</span> &#123;</span><br><span class="line">    <span class="comment">// 1. 确保内部容量</span></span><br><span class="line">    ensureCapacityInternal(size + <span class="number">1</span>);  <span class="comment">// Increments modCount!!</span></span><br><span class="line">    <span class="comment">// 2. 添加元素到 elementData 中，同时 size + 1</span></span><br><span class="line">    elementData[size++] = e;</span><br><span class="line">    <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ol start="2"><li>确保内部容量</li></ol><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title function_">ensureCapacityInternal</span><span class="params">(<span class="type">int</span> minCapacity)</span> &#123;</span><br><span class="line">    <span class="comment">// 1. 先计算容量大小 calculateCapacity(elementData, minCapacity)</span></span><br><span class="line">    <span class="comment">// 2. 确保具体容量</span></span><br><span class="line">    ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">private</span> <span class="keyword">static</span> <span class="type">int</span> <span class="title function_">calculateCapacity</span><span class="params">(Object[] elementData, <span class="type">int</span> minCapacity)</span> &#123;</span><br><span class="line">    <span class="keyword">if</span> (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) &#123; <span class="comment">// 判断 elementData 是不是 默认容量空数组（和空数组 EMPTY_ELEMENTDATA 做区分）</span></span><br><span class="line">        <span class="keyword">return</span> Math.max(DEFAULT_CAPACITY, minCapacity); <span class="comment">// 是的话，返回当前容量为 默认容量 和 用户自己传入的最小容量 的最大值</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> minCapacity; <span class="comment">// 走这里，否则返回 用户自己传入的最小容量</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ol start="3"><li>确保具体容量</li></ol><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title function_">ensureExplicitCapacity</span><span class="params">(<span class="type">int</span> minCapacity)</span> &#123;</span><br><span class="line">    modCount++; <span class="comment">// 首先并发修改数 + 1，定义在 AbstractList 中，protected transient int modCount = 0; 用于是否出现了判断修改</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">// overflow-conscious code</span></span><br><span class="line">    <span class="comment">// 如果我们传入的最小容量 - elementData 数组长度 &gt; 0，则进行扩容</span></span><br><span class="line">    <span class="keyword">if</span> (minCapacity - elementData.length &gt; <span class="number">0</span>)</span><br><span class="line">        <span class="comment">// 扩容方法</span></span><br><span class="line">        grow(minCapacity);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ol start="4"><li>扩容</li></ol><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment">     * The maximum size of array to allocate.</span></span><br><span class="line"><span class="comment">     * Some VMs reserve some header words in an array.</span></span><br><span class="line"><span class="comment">     * Attempts to allocate larger arrays may result in</span></span><br><span class="line"><span class="comment">     * OutOfMemoryError: Requested array size exceeds VM limit</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">int</span> <span class="variable">MAX_ARRAY_SIZE</span> <span class="operator">=</span> Integer.MAX_VALUE - <span class="number">8</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Increases the capacity to ensure that it can hold at least the</span></span><br><span class="line"><span class="comment"> * number of elements specified by the minimum capacity argument.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> minCapacity the desired minimum capacity</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title function_">grow</span><span class="params">(<span class="type">int</span> minCapacity)</span> &#123;</span><br><span class="line">    <span class="comment">// overflow-conscious code</span></span><br><span class="line">    <span class="comment">// 旧容量</span></span><br><span class="line">    <span class="type">int</span> <span class="variable">oldCapacity</span> <span class="operator">=</span> elementData.length;</span><br><span class="line">    <span class="comment">// 新容量，扩容为旧容量的 近似 1.5 倍【注意】</span></span><br><span class="line">    <span class="type">int</span> <span class="variable">newCapacity</span> <span class="operator">=</span> oldCapacity + (oldCapacity &gt;&gt; <span class="number">1</span>);</span><br><span class="line">    <span class="comment">// 扩容之后的新容量还是 小于 我们传入的最小容量，那把 minCapacity 作为我们的新容量</span></span><br><span class="line">    <span class="keyword">if</span> (newCapacity - minCapacity &lt; <span class="number">0</span>)</span><br><span class="line">        newCapacity = minCapacity;</span><br><span class="line">    <span class="comment">// 如果 新容量 大于 最小数组大小（int 最大值 - 8），那么执行 hugeCapacity(minCapacity); 扩容为 int 最大值</span></span><br><span class="line">    <span class="keyword">if</span> (newCapacity - MAX_ARRAY_SIZE &gt; <span class="number">0</span>) <span class="comment">// Integer.MAX_VALUE - 8;</span></span><br><span class="line">        newCapacity = hugeCapacity(minCapacity);</span><br><span class="line">    <span class="comment">// minCapacity is usually close to size, so this is a win:</span></span><br><span class="line">    <span class="comment">// 开辟新数组，并将原数组的内容拷贝到新数组中，最后再赋值给 elementData</span></span><br><span class="line">    elementData = Arrays.copyOf(elementData, newCapacity);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ol start="5"><li>最大化扩容</li></ol><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> <span class="keyword">static</span> <span class="type">int</span> <span class="title function_">hugeCapacity</span><span class="params">(<span class="type">int</span> minCapacity)</span> &#123;</span><br><span class="line">    <span class="keyword">if</span> (minCapacity &lt; <span class="number">0</span>) <span class="comment">// overflow</span></span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">OutOfMemoryError</span>();</span><br><span class="line">    <span class="comment">// 如果我们传入的最小容量 大于 最大数组大小，就扩容为 int 最大值</span></span><br><span class="line">    <span class="keyword">return</span> (minCapacity &gt; MAX_ARRAY_SIZE) ?</span><br><span class="line">        Integer.MAX_VALUE :</span><br><span class="line">    MAX_ARRAY_SIZE;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>当我们使用空参构造器时，<code>ArrayList&lt;Object&gt; list = new ArrayList&lt;&gt;();</code></p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">List&lt;Object&gt; list = <span class="keyword">new</span> <span class="title class_">ArrayList</span>&lt;&gt;();</span><br><span class="line">list.add(<span class="string">&quot;a&quot;</span>); <span class="comment">// 第 1 次 add</span></span><br><span class="line">list.add(<span class="string">&quot;b&quot;</span>); list.add(<span class="string">&quot;c&quot;</span>); list.add(<span class="string">&quot;d&quot;</span>); list.add(<span class="string">&quot;e&quot;</span>); </span><br><span class="line">list.add(<span class="string">&quot;f&quot;</span>); list.add(<span class="string">&quot;g&quot;</span>); list.add(<span class="string">&quot;h&quot;</span>);list.add(<span class="string">&quot;i&quot;</span>);</span><br><span class="line">list.add(<span class="string">&quot;j&quot;</span>); <span class="comment">// 第 10 次 add</span></span><br></pre></td></tr></table></figure><ol start="0"><li>执行空参构造器，创建 ArrayList 对象</li></ol><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Constructs an empty list with an initial capacity of ten.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="title function_">ArrayList</span><span class="params">()</span> &#123;</span><br><span class="line">    <span class="built_in">this</span>.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; <span class="comment">// DEFAULTCAPACITY_EMPTY_ELEMENTDATA 赋值给 elementData</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ol><li>执行第一步 <code>add(E e)</code></li></ol><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">add</span><span class="params">(E e)</span> &#123;</span><br><span class="line">    ensureCapacityInternal(size + <span class="number">1</span>);  <span class="comment">// Increments modCount!!</span></span><br><span class="line">    elementData[size++] = e;</span><br><span class="line">    <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ol start="2"><li>确保内部容量</li></ol><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title function_">ensureCapacityInternal</span><span class="params">(<span class="type">int</span> minCapacity)</span> &#123;</span><br><span class="line">    ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">private</span> <span class="keyword">static</span> <span class="type">int</span> <span class="title function_">calculateCapacity</span><span class="params">(Object[] elementData, <span class="type">int</span> minCapacity)</span> &#123;</span><br><span class="line">    <span class="comment">// 走这里</span></span><br><span class="line">    <span class="keyword">if</span> (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) &#123; <span class="comment">// 判断 elementData 是不是 默认容量空数组（和空数组 EMPTY_ELEMENTDATA 做区分）</span></span><br><span class="line">        <span class="keyword">return</span> Math.max(DEFAULT_CAPACITY, minCapacity); <span class="comment">// 是的话，返回当前容量为 默认容量 和 用户自己传入的最小容量 0 + 1 的最大值，那么就是 10</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> minCapacity; <span class="comment">// 否则返回 用户自己传入的最小容量</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ol start="3"><li><p>确保具体容量</p></li><li><p>然后执行一次扩容，扩容为 10，可以容量 10 个数，所以只会进行一次扩容</p></li></ol><h2 id="关于创建-ArrayList-的几种方式常见问题"><a href="#关于创建-ArrayList-的几种方式常见问题" class="headerlink" title="关于创建 ArrayList 的几种方式常见问题"></a>关于创建 ArrayList 的几种方式常见问题</h2><h3 id="第一种：new-对象，调用-ArrayList-的构造器，这个没啥说法"><a href="#第一种：new-对象，调用-ArrayList-的构造器，这个没啥说法" class="headerlink" title="第一种：new 对象，调用 ArrayList 的构造器，这个没啥说法"></a>第一种：new 对象，调用 ArrayList 的构造器，这个没啥说法</h3><h3 id="第二种：调用-Arrays-工具类的-asList-方法，可以初始化一个-List"><a href="#第二种：调用-Arrays-工具类的-asList-方法，可以初始化一个-List" class="headerlink" title="第二种：调用 Arrays 工具类的 asList() 方法，可以初始化一个 List"></a>第二种：调用 Arrays 工具类的 asList() 方法，可以初始化一个 List</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">List&lt;String&gt; list2 = Arrays.asList(<span class="string">&quot;a&quot;</span>, <span class="string">&quot;b&quot;</span>, <span class="string">&quot;c&quot;</span>); <span class="comment">// 创建方式没有问题</span></span><br><span class="line">list2.add(<span class="string">&quot;d&quot;</span>); <span class="comment">// 但是不能调用 add() 方法，为什么？</span></span><br></pre></td></tr></table></figure><p>为什么通过 Arrays 创建的 List 不能调用 add 方法呢？同时 remove() 方法也不能调用。</p><p>下面看源码：</p><ol><li><p>asList() 方法</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> &lt;T&gt; List&lt;T&gt; <span class="title function_">asList</span><span class="params">(T... a)</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">ArrayList</span>&lt;&gt;(a);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li><li><p>ArrayList 的构造器</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@serial</span> include</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">ArrayList</span>&lt;E&gt; <span class="keyword">extends</span> <span class="title class_">AbstractList</span>&lt;E&gt;</span><br><span class="line">    <span class="keyword">implements</span> <span class="title class_">RandomAccess</span>, java.io.Serializable</span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">long</span> <span class="variable">serialVersionUID</span> <span class="operator">=</span> -<span class="number">2764017481108945198L</span>;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> E[] a;</span><br><span class="line"></span><br><span class="line">    ArrayList(E[] array) &#123;</span><br><span class="line">        a = Objects.requireNonNull(array);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// ...</span></span><br><span class="line">    </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>发现调用的是 <strong>Arrays 类自己创建的内部类</strong> ArrayList 的构造器，而这个 ArrayList 中并没有重写 add() 方法，虽然它继承了 AbstractList 抽象类，但是 AbstractList 中的抽象类的 add() 方法的默认实现是直接抛异常，同理 remove() 方法也没有重写，继承抽奖类的也是直接抛异常，而 get()、set() 获取和修改可以使用，原因就是重写了对应方法。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">add</span><span class="params">(E e)</span> &#123;</span><br><span class="line">    add(size(), e);</span><br><span class="line">    <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">add</span><span class="params">(<span class="type">int</span> index, E element)</span> &#123;</span><br><span class="line">    <span class="comment">// 添加直接抛异常</span></span><br><span class="line">    <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">UnsupportedOperationException</span>();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> E <span class="title function_">remove</span><span class="params">(<span class="type">int</span> index)</span> &#123;</span><br><span class="line">    <span class="comment">// 删除直接抛异常</span></span><br><span class="line">    <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">UnsupportedOperationException</span>();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li></ol><p>那什么时候会用这种方式创建 List 呢？</p><ul><li>当我们使用<strong>固定大小</strong>的 List 且<strong>不做增加和删除，只做修改</strong>的时候可以使用这种方式。</li></ul><h3 id="第三种：调用-Collections-工具类的-emptyList-方法，初始化一个空的-List【基本不用】"><a href="#第三种：调用-Collections-工具类的-emptyList-方法，初始化一个空的-List【基本不用】" class="headerlink" title="第三种：调用 Collections 工具类的 emptyList() 方法，初始化一个空的 List【基本不用】"></a>第三种：调用 Collections 工具类的 emptyList() 方法，初始化一个空的 List【基本不用】</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">ArrayList&lt;String&gt; list = Collections.emptyList(); <span class="comment">// 创建一个 EmptyList，空的 List</span></span><br><span class="line">list.add(<span class="string">&quot;a&quot;</span>); <span class="comment">// 不能调用 add() 方法</span></span><br></pre></td></tr></table></figure><p>不能调用 add() 的原因和第二种方式的原因时类似的</p><p>看源码：</p><ol><li><p>emptyList() 方法，直接返回一个 EMPTY_LIST</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> &lt;T&gt; List&lt;T&gt; <span class="title function_">emptyList</span><span class="params">()</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> (List&lt;T&gt;) EMPTY_LIST;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">List</span> <span class="variable">EMPTY_LIST</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">EmptyList</span>&lt;&gt;();</span><br></pre></td></tr></table></figure></li><li><p>再看 EmptyList 类</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment">  * <span class="doctag">@serial</span> include</span></span><br><span class="line"><span class="comment">  */</span></span><br><span class="line"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">EmptyList</span>&lt;E&gt;</span><br><span class="line">    <span class="keyword">extends</span> <span class="title class_">AbstractList</span>&lt;E&gt;</span><br><span class="line">    <span class="keyword">implements</span> <span class="title class_">RandomAccess</span>, Serializable &#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">long</span> <span class="variable">serialVersionUID</span> <span class="operator">=</span> <span class="number">8842843931221139166L</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> Iterator&lt;E&gt; <span class="title function_">iterator</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> emptyIterator();</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">public</span> ListIterator&lt;E&gt; <span class="title function_">listIterator</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> emptyListIterator();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">size</span><span class="params">()</span> &#123;<span class="keyword">return</span> <span class="number">0</span>;&#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">isEmpty</span><span class="params">()</span> &#123;<span class="keyword">return</span> <span class="literal">true</span>;&#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// ...</span></span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>它也是一个内部类，同样的继承了 AbstractList，但是没有重写 add()、set()、remove()，所以无法添加元素，什么都不能干，还真就是一个空的 List，没什么用。</p></li></ol><p>使用场景？</p><ul><li>当我们代码中要返回空 List 的时候才会用到，<code>public static final List EMPTY_LIST = new EmptyList&lt;&gt;();</code> 在 javac 编译成 class 文件的时候就已经初始化了，比 new ArrayList() 每次返回空 List 要好，因为不需要重新创建对象。</li></ul><h2 id="trimToSize"><a href="#trimToSize" class="headerlink" title="trimToSize()"></a>trimToSize()</h2><p>剪切 ArrayList 让它的容量变成 size，将没有元素的位置删掉，底层还是 Arrays.copy()</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment">     * Trims the capacity of this &lt;tt&gt;ArrayList&lt;/tt&gt; instance to be the</span></span><br><span class="line"><span class="comment">     * list&#x27;s current size.  An application can use this operation to minimize</span></span><br><span class="line"><span class="comment">     * the storage of an &lt;tt&gt;ArrayList&lt;/tt&gt; instance.</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">trimToSize</span><span class="params">()</span> &#123;</span><br><span class="line">    modCount++;</span><br><span class="line">    <span class="keyword">if</span> (size &lt; elementData.length) &#123;</span><br><span class="line">        elementData = (size == <span class="number">0</span>)</span><br><span class="line">            ? EMPTY_ELEMENTDATA</span><br><span class="line">            : Arrays.copyOf(elementData, size);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="contains-Object-o-、indexOf-int-index-、lastIndexOf-int-index"><a href="#contains-Object-o-、indexOf-int-index-、lastIndexOf-int-index" class="headerlink" title="contains(Object o)、indexOf(int index)、lastIndexOf(int index)"></a>contains(Object o)、indexOf(int index)、lastIndexOf(int index)</h2><p><code>contains(Object o)</code> 源码</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment">     * Returns &lt;tt&gt;true&lt;/tt&gt; if this list contains the specified element.</span></span><br><span class="line"><span class="comment">     * More formally, returns &lt;tt&gt;true&lt;/tt&gt; if and only if this list contains</span></span><br><span class="line"><span class="comment">     * at least one element &lt;tt&gt;e&lt;/tt&gt; such that</span></span><br><span class="line"><span class="comment">     * &lt;tt&gt;(o==null&amp;nbsp;?&amp;nbsp;e==null&amp;nbsp;:&amp;nbsp;o.equals(e))&lt;/tt&gt;.</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> o element whose presence in this list is to be tested</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> &lt;tt&gt;true&lt;/tt&gt; if this list contains the specified element</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line"><span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">contains</span><span class="params">(Object o)</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> indexOf(o) &gt;= <span class="number">0</span>; <span class="comment">// 这里调用 indexOf(o)，判断返回索引是否 大于等于 0，如果是则包含，否则不包含</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><code>indexOf(int index)</code> 源码</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment">     * Returns the index of the first occurrence of the specified element</span></span><br><span class="line"><span class="comment">     * in this list, or -1 if this list does not contain the element.</span></span><br><span class="line"><span class="comment">     * More formally, returns the lowest index &lt;tt&gt;i&lt;/tt&gt; such that</span></span><br><span class="line"><span class="comment">     * &lt;tt&gt;(o==null&amp;nbsp;?&amp;nbsp;get(i)==null&amp;nbsp;:&amp;nbsp;o.equals(get(i)))&lt;/tt&gt;,</span></span><br><span class="line"><span class="comment">     * or -1 if there is no such index.</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line"><span class="keyword">public</span> <span class="type">int</span> <span class="title function_">indexOf</span><span class="params">(Object o)</span> &#123;</span><br><span class="line">    <span class="keyword">if</span> (o == <span class="literal">null</span>) &#123; <span class="comment">// 如果是空，遍历等于空的位置，找到第一个返回</span></span><br><span class="line">        <span class="keyword">for</span> (<span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> <span class="number">0</span>; i &lt; size; i++)</span><br><span class="line">            <span class="keyword">if</span> (elementData[i]==<span class="literal">null</span>)</span><br><span class="line">                <span class="keyword">return</span> i;</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123; <span class="comment">// 如果不是空，同样是 for 循环遍历，找到第一个返回</span></span><br><span class="line">        <span class="keyword">for</span> (<span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> <span class="number">0</span>; i &lt; size; i++)</span><br><span class="line">            <span class="keyword">if</span> (o.equals(elementData[i]))</span><br><span class="line">                <span class="keyword">return</span> i;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> -<span class="number">1</span>; <span class="comment">// 找不到返回 -1</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><code>lastIndexOf(int index)</code> 源码</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment">     * Returns the index of the last occurrence of the specified element</span></span><br><span class="line"><span class="comment">     * in this list, or -1 if this list does not contain the element.</span></span><br><span class="line"><span class="comment">     * More formally, returns the highest index &lt;tt&gt;i&lt;/tt&gt; such that</span></span><br><span class="line"><span class="comment">     * &lt;tt&gt;(o==null&amp;nbsp;?&amp;nbsp;get(i)==null&amp;nbsp;:&amp;nbsp;o.equals(get(i)))&lt;/tt&gt;,</span></span><br><span class="line"><span class="comment">     * or -1 if there is no such index.</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line"><span class="keyword">public</span> <span class="type">int</span> <span class="title function_">lastIndexOf</span><span class="params">(Object o)</span> &#123;</span><br><span class="line">    <span class="keyword">if</span> (o == <span class="literal">null</span>) &#123;</span><br><span class="line">        <span class="keyword">for</span> (<span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> size-<span class="number">1</span>; i &gt;= <span class="number">0</span>; i--)</span><br><span class="line">            <span class="keyword">if</span> (elementData[i]==<span class="literal">null</span>)</span><br><span class="line">                <span class="keyword">return</span> i;</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        <span class="keyword">for</span> (<span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> size-<span class="number">1</span>; i &gt;= <span class="number">0</span>; i--)</span><br><span class="line">            <span class="keyword">if</span> (o.equals(elementData[i]))</span><br><span class="line">                <span class="keyword">return</span> i;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> -<span class="number">1</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="clone"><a href="#clone" class="headerlink" title="clone()"></a>clone()</h2><p>ArrayList 的克隆方法，用的是父类 Object 的 clone() 方法，所以是<strong>浅拷贝</strong>，只拷贝值，不创建对象。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment">     * Returns a shallow copy of this &lt;tt&gt;ArrayList&lt;/tt&gt; instance.  (The</span></span><br><span class="line"><span class="comment">     * elements themselves are not copied.)</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> a clone of this &lt;tt&gt;ArrayList&lt;/tt&gt; instance</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line"><span class="keyword">public</span> Object <span class="title function_">clone</span><span class="params">()</span> &#123;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        ArrayList&lt;?&gt; v = (ArrayList&lt;?&gt;) <span class="built_in">super</span>.clone(); <span class="comment">// 调用父类 clone()</span></span><br><span class="line">        v.elementData = Arrays.copyOf(elementData, size); <span class="comment">// Arrays.copy 拷贝</span></span><br><span class="line">        v.modCount = <span class="number">0</span>; <span class="comment">// 克隆之后认为是一个新的 ArrayList，没有被修改过</span></span><br><span class="line">        <span class="keyword">return</span> v;</span><br><span class="line">    &#125; <span class="keyword">catch</span> (CloneNotSupportedException e) &#123;</span><br><span class="line">        <span class="comment">// this shouldn&#x27;t happen, since we are Cloneable</span></span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">InternalError</span>(e);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="toArray"><a href="#toArray" class="headerlink" title="toArray()"></a>toArray()</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment">     * Returns an array containing all of the elements in this list</span></span><br><span class="line"><span class="comment">     * in proper sequence (from first to last element).</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * &lt;p&gt;The returned array will be &quot;safe&quot; in that no references to it are</span></span><br><span class="line"><span class="comment">     * maintained by this list.  (In other words, this method must allocate</span></span><br><span class="line"><span class="comment">     * a new array).  The caller is thus free to modify the returned array.</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * &lt;p&gt;This method acts as bridge between array-based and collection-based</span></span><br><span class="line"><span class="comment">     * APIs.</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> an array containing all of the elements in this list in</span></span><br><span class="line"><span class="comment">     *         proper sequence</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line"><span class="keyword">public</span> Object[] toArray() &#123;</span><br><span class="line">    <span class="keyword">return</span> Arrays.copyOf(elementData, size);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 泛型实现 T 是类型，E 是元素，U 是</span></span><br><span class="line"><span class="keyword">public</span> &lt;T&gt; T[] toArray(T[] a) &#123;</span><br><span class="line">    <span class="keyword">if</span> (a.length &lt; size)</span><br><span class="line">        <span class="comment">// Make a new array of a&#x27;s runtime type, but my contents:</span></span><br><span class="line">        <span class="keyword">return</span> (T[]) Arrays.copyOf(elementData, size, a.getClass());</span><br><span class="line">    <span class="comment">// 调用的也是 System.arraycopy</span></span><br><span class="line">    System.arraycopy(elementData, <span class="number">0</span>, a, <span class="number">0</span>, size);</span><br><span class="line">    <span class="keyword">if</span> (a.length &gt; size)</span><br><span class="line">        a[size] = <span class="literal">null</span>;</span><br><span class="line">    <span class="keyword">return</span> a;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Arrays.copy()</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> &lt;T&gt; T[] copyOf(T[] original, <span class="type">int</span> newLength) &#123;</span><br><span class="line">    <span class="keyword">return</span> (T[]) copyOf(original, newLength, original.getClass());</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> &lt;T,U&gt; T[] copyOf(U[] original, <span class="type">int</span> newLength, Class&lt;? <span class="keyword">extends</span> <span class="title class_">T</span>[]&gt; newType) &#123;</span><br><span class="line">    <span class="meta">@SuppressWarnings(&quot;unchecked&quot;)</span></span><br><span class="line">    T[] copy = ((Object)newType == (Object)Object[].class)</span><br><span class="line">        ? (T[]) <span class="keyword">new</span> <span class="title class_">Object</span>[newLength]</span><br><span class="line">        : (T[]) Array.newInstance(newType.getComponentType(), newLength);</span><br><span class="line">    <span class="comment">// 真正执行 copy 的是这句话，System.arraycopy</span></span><br><span class="line">    System.arraycopy(original, <span class="number">0</span>, copy, <span class="number">0</span>,</span><br><span class="line">                     Math.min(original.length, newLength));</span><br><span class="line">    <span class="keyword">return</span> copy;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// native 实现，底层可能是 C++ 写的</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">native</span> <span class="keyword">void</span> <span class="title function_">arraycopy</span><span class="params">(Object src,  <span class="type">int</span>  srcPos,</span></span><br><span class="line"><span class="params">                                        Object dest, <span class="type">int</span> destPos,</span></span><br><span class="line"><span class="params">                                        <span class="type">int</span> length)</span>;</span><br></pre></td></tr></table></figure><h2 id="get-index"><a href="#get-index" class="headerlink" title="get(index)"></a>get(index)</h2><p>对通过下标取数组元素做的一个封装 elementData(index)</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@SuppressWarnings(&quot;unchecked&quot;)</span></span><br><span class="line">E <span class="title function_">elementData</span><span class="params">(<span class="type">int</span> index)</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> (E) elementData[index]; <span class="comment">// 底层还是数组访问</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><code>get(index)</code></p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment">     * Returns the element at the specified position in this list.</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span>  index index of the element to return</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> the element at the specified position in this list</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@throws</span> IndexOutOfBoundsException &#123;<span class="doctag">@inheritDoc</span>&#125;</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line"><span class="keyword">public</span> E <span class="title function_">get</span><span class="params">(<span class="type">int</span> index)</span> &#123;</span><br><span class="line">    rangeCheck(index); <span class="comment">// 索引范围检查，不合法抛出下标越界异常</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> elementData(index); <span class="comment">// 返回索引对应的值</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment">     * Checks if the given index is in range.  If not, throws an appropriate</span></span><br><span class="line"><span class="comment">     * runtime exception.  This method does *not* check if the index is</span></span><br><span class="line"><span class="comment">     * negative: It is always used immediately prior to an array access,</span></span><br><span class="line"><span class="comment">     * which throws an ArrayIndexOutOfBoundsException if index is negative.</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title function_">rangeCheck</span><span class="params">(<span class="type">int</span> index)</span> &#123;</span><br><span class="line">    <span class="keyword">if</span> (index &gt;= size) <span class="comment">// 索引不合法抛出 IndexOutOfBoundsException 异常</span></span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">IndexOutOfBoundsException</span>(outOfBoundsMsg(index));</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="set-index"><a href="#set-index" class="headerlink" title="set(index)"></a>set(index)</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment">     * Replaces the element at the specified position in this list with</span></span><br><span class="line"><span class="comment">     * the specified element.</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> index index of the element to replace</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> element element to be stored at the specified position</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> the element previously at the specified position</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@throws</span> IndexOutOfBoundsException &#123;<span class="doctag">@inheritDoc</span>&#125;</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line"><span class="keyword">public</span> E <span class="title function_">set</span><span class="params">(<span class="type">int</span> index, E element)</span> &#123;</span><br><span class="line">    rangeCheck(index); <span class="comment">// 索引范围检查</span></span><br><span class="line"></span><br><span class="line">    <span class="type">E</span> <span class="variable">oldValue</span> <span class="operator">=</span> elementData(index); <span class="comment">// 先获取旧值</span></span><br><span class="line">    elementData[index] = element; <span class="comment">// 再赋新值</span></span><br><span class="line">    <span class="keyword">return</span> oldValue; <span class="comment">// 返回旧值</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="add-index-E-插入"><a href="#add-index-E-插入" class="headerlink" title="add(index, E) 插入"></a>add(index, E) 插入</h2><p>每插入一次都会触发一次 arraycopy 数组移动，O(n) 的复杂度，比较耗费性能。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment">     * Inserts the specified element at the specified position in this</span></span><br><span class="line"><span class="comment">     * list. Shifts the element currently at that position (if any) and</span></span><br><span class="line"><span class="comment">     * any subsequent elements to the right (adds one to their indices).</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> index index at which the specified element is to be inserted</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> element element to be inserted</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@throws</span> IndexOutOfBoundsException &#123;<span class="doctag">@inheritDoc</span>&#125;</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">add</span><span class="params">(<span class="type">int</span> index, E element)</span> &#123;</span><br><span class="line">    rangeCheckForAdd(index); <span class="comment">// 插入索引范围检查</span></span><br><span class="line"></span><br><span class="line">    ensureCapacityInternal(size + <span class="number">1</span>);  <span class="comment">// Increments modCount!!</span></span><br><span class="line">    System.arraycopy(elementData, index, elementData, index + <span class="number">1</span>,</span><br><span class="line">                     size - index); <span class="comment">// [index, size) 往后移动一位</span></span><br><span class="line">    elementData[index] = element; <span class="comment">// 插入到 index 位置上</span></span><br><span class="line">    size++; <span class="comment">// 容量 + 1</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment">     * A version of rangeCheck used by add and addAll.</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title function_">rangeCheckForAdd</span><span class="params">(<span class="type">int</span> index)</span> &#123;</span><br><span class="line">    <span class="keyword">if</span> (index &gt; size || index &lt; <span class="number">0</span>) <span class="comment">// 插入索引范围检查，这里有一个优化的地方：把常用的判断条件放前边，提高性能</span></span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">IndexOutOfBoundsException</span>(outOfBoundsMsg(index));</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment">     * Constructs an IndexOutOfBoundsException detail message.</span></span><br><span class="line"><span class="comment">     * Of the many possible refactorings of the error handling code,</span></span><br><span class="line"><span class="comment">     * this &quot;outlining&quot; performs best with both server and client VMs.</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line"><span class="keyword">private</span> String <span class="title function_">outOfBoundsMsg</span><span class="params">(<span class="type">int</span> index)</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="string">&quot;Index: &quot;</span>+index+<span class="string">&quot;, Size: &quot;</span>+size; <span class="comment">// 对于短字符串用 + 号最快，对于大量字符串拼接用 StringBuilder</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="remove-int-index-、remove-Object-o"><a href="#remove-int-index-、remove-Object-o" class="headerlink" title="remove(int index)、remove(Object o)"></a>remove(int index)、remove(Object o)</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment">     * Removes the element at the specified position in this list.</span></span><br><span class="line"><span class="comment">     * Shifts any subsequent elements to the left (subtracts one from their</span></span><br><span class="line"><span class="comment">     * indices).</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> index the index of the element to be removed</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> the element that was removed from the list</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@throws</span> IndexOutOfBoundsException &#123;<span class="doctag">@inheritDoc</span>&#125;</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line"><span class="comment">// 根据索引删除</span></span><br><span class="line"><span class="keyword">public</span> E <span class="title function_">remove</span><span class="params">(<span class="type">int</span> index)</span> &#123;</span><br><span class="line">    rangeCheck(index); <span class="comment">// 索引范围检查</span></span><br><span class="line"></span><br><span class="line">    modCount++; <span class="comment">// 修改次数 + 1</span></span><br><span class="line">    <span class="type">E</span> <span class="variable">oldValue</span> <span class="operator">=</span> elementData(index); <span class="comment">// 先获取旧值用于返回</span></span><br><span class="line"></span><br><span class="line">    <span class="type">int</span> <span class="variable">numMoved</span> <span class="operator">=</span> size - index - <span class="number">1</span>; <span class="comment">// numMoved 是删除 index 上的数后需要移动的元素的个数</span></span><br><span class="line">    <span class="keyword">if</span> (numMoved &gt; <span class="number">0</span>)</span><br><span class="line">        System.arraycopy(elementData, index+<span class="number">1</span>, elementData, index,</span><br><span class="line">                         numMoved); <span class="comment">// 又是一个 arraycopy</span></span><br><span class="line">    elementData[--size] = <span class="literal">null</span>; <span class="comment">// clear to let GC do its work，容量 - 1 并且最后一个元素指向空，表示不可达，等待下次垃圾回收</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> oldValue;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment">     * Removes the first occurrence of the specified element from this list,</span></span><br><span class="line"><span class="comment">     * if it is present.  If the list does not contain the element, it is</span></span><br><span class="line"><span class="comment">     * unchanged.  More formally, removes the element with the lowest index</span></span><br><span class="line"><span class="comment">     * &lt;tt&gt;i&lt;/tt&gt; such that</span></span><br><span class="line"><span class="comment">     * &lt;tt&gt;(o==null&amp;nbsp;?&amp;nbsp;get(i)==null&amp;nbsp;:&amp;nbsp;o.equals(get(i)))&lt;/tt&gt;</span></span><br><span class="line"><span class="comment">     * (if such an element exists).  Returns &lt;tt&gt;true&lt;/tt&gt; if this list</span></span><br><span class="line"><span class="comment">     * contained the specified element (or equivalently, if this list</span></span><br><span class="line"><span class="comment">     * changed as a result of the call).</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> o element to be removed from this list, if present</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> &lt;tt&gt;true&lt;/tt&gt; if this list contained the specified element</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line"><span class="comment">// 删除指定对象，如果有多个，删除第一个</span></span><br><span class="line"><span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">remove</span><span class="params">(Object o)</span> &#123; <span class="comment">// 这里和 contains(Object o) 实现类似</span></span><br><span class="line">    <span class="comment">// for 循环遍历，找到第一个相等的元素删除</span></span><br><span class="line">    <span class="keyword">if</span> (o == <span class="literal">null</span>) &#123;</span><br><span class="line">        <span class="keyword">for</span> (<span class="type">int</span> <span class="variable">index</span> <span class="operator">=</span> <span class="number">0</span>; index &lt; size; index++)</span><br><span class="line">            <span class="keyword">if</span> (elementData[index] == <span class="literal">null</span>) &#123;</span><br><span class="line">                fastRemove(index); <span class="comment">// 这里调用 fastRemove() 方法进行删除当前元素</span></span><br><span class="line">                <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">            &#125;</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        <span class="keyword">for</span> (<span class="type">int</span> <span class="variable">index</span> <span class="operator">=</span> <span class="number">0</span>; index &lt; size; index++)</span><br><span class="line">            <span class="keyword">if</span> (o.equals(elementData[index])) &#123;</span><br><span class="line">                fastRemove(index);</span><br><span class="line">                <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">            &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">     * Private remove method that skips bounds checking and does not</span></span><br><span class="line"><span class="comment">     * return the value removed.</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line"><span class="comment">// 发现和 remove(index) 思路一样啊，也是 arraycopy 移动元素，</span></span><br><span class="line"><span class="comment">// 然名字是 fastRemove() 但是实现上并没有变快，就是一个名字而已，因为要多次调用，所以抽取成了一个方法</span></span><br><span class="line"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title function_">fastRemove</span><span class="params">(<span class="type">int</span> index)</span> &#123;</span><br><span class="line">    modCount++;</span><br><span class="line">    <span class="type">int</span> <span class="variable">numMoved</span> <span class="operator">=</span> size - index - <span class="number">1</span>;</span><br><span class="line">    <span class="keyword">if</span> (numMoved &gt; <span class="number">0</span>)</span><br><span class="line">        System.arraycopy(elementData, index+<span class="number">1</span>, elementData, index,</span><br><span class="line">                         numMoved);</span><br><span class="line">    elementData[--size] = <span class="literal">null</span>; <span class="comment">// clear to let GC do its work</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="clear"><a href="#clear" class="headerlink" title="clear()"></a>clear()</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment">     * Removes all of the elements from this list.  The list will</span></span><br><span class="line"><span class="comment">     * be empty after this call returns.</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line"><span class="comment">// 清空 List</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">clear</span><span class="params">()</span> &#123;</span><br><span class="line">    modCount++; <span class="comment">// 清空也是一次修改</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">// 将每个元素置空，等待 GC 回收</span></span><br><span class="line">    <span class="comment">// clear to let GC do its work</span></span><br><span class="line">    <span class="keyword">for</span> (<span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> <span class="number">0</span>; i &lt; size; i++)</span><br><span class="line">        elementData[i] = <span class="literal">null</span>;</span><br><span class="line"></span><br><span class="line">    size = <span class="number">0</span>; <span class="comment">// size 置为 0</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>延伸：下面这段代码扩容几次？</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">List&lt;Object&gt; list = <span class="keyword">new</span> <span class="title class_">ArrayList</span>&lt;&gt;();</span><br><span class="line">list.add(<span class="string">&quot;a&quot;</span>); </span><br><span class="line">list.clear();</span><br><span class="line">list.add(<span class="string">&quot;a&quot;</span>);</span><br></pre></td></tr></table></figure><p>答案：<strong>扩容 1 次</strong>，创建空的 ArrayList()，第一次添加元素会进行 1 次扩容，扩容为 10，然后 clear() 清空 List 之后，只是把数组中的元素个数 size 置为 0，再次添加此时 elementData 数组的长度还是 10，所以不会执行扩容。</p><p>所以当我们还要复用这个 List 的时候，就可以使用 clear()，而不建议使用 new ArrayList() 的方式，因为它每次会进行一次扩容。</p><h2 id="addAll-Collection-lt-extends-E-gt-c-、addAll-int-index-Collection-lt-extends-E-gt-c"><a href="#addAll-Collection-lt-extends-E-gt-c-、addAll-int-index-Collection-lt-extends-E-gt-c" class="headerlink" title="addAll(Collection&lt;? extends E&gt; c)、addAll(int index, Collection&lt;? extends E&gt; c)"></a>addAll(Collection&lt;? extends E&gt; c)、addAll(int index, Collection&lt;? extends E&gt; c)</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment">     * Appends all of the elements in the specified collection to the end of</span></span><br><span class="line"><span class="comment">     * this list, in the order that they are returned by the</span></span><br><span class="line"><span class="comment">     * specified collection&#x27;s Iterator.  The behavior of this operation is</span></span><br><span class="line"><span class="comment">     * undefined if the specified collection is modified while the operation</span></span><br><span class="line"><span class="comment">     * is in progress.  (This implies that the behavior of this call is</span></span><br><span class="line"><span class="comment">     * undefined if the specified collection is this list, and this</span></span><br><span class="line"><span class="comment">     * list is nonempty.)</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> c collection containing elements to be added to this list</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> &lt;tt&gt;true&lt;/tt&gt; if this list changed as a result of the call</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@throws</span> NullPointerException if the specified collection is null</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line"><span class="comment">// 向 List 中添加一个 List</span></span><br><span class="line"><span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">addAll</span><span class="params">(Collection&lt;? extends E&gt; c)</span> &#123;</span><br><span class="line">    Object[] a = c.toArray();</span><br><span class="line">    <span class="type">int</span> <span class="variable">numNew</span> <span class="operator">=</span> a.length;</span><br><span class="line">    <span class="comment">// 确保内部容量</span></span><br><span class="line">    ensureCapacityInternal(size + numNew);  <span class="comment">// Increments modCount</span></span><br><span class="line">    System.arraycopy(a, <span class="number">0</span>, elementData, size, numNew); <span class="comment">// 数组拷贝，把 a 数组放到 elementData 数组后面</span></span><br><span class="line">    size += numNew; <span class="comment">// 元素个数 + numNew</span></span><br><span class="line">    <span class="keyword">return</span> numNew != <span class="number">0</span>; <span class="comment">// 如果不是 0 就可以添加成功</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment">     * Inserts all of the elements in the specified collection into this</span></span><br><span class="line"><span class="comment">     * list, starting at the specified position.  Shifts the element</span></span><br><span class="line"><span class="comment">     * currently at that position (if any) and any subsequent elements to</span></span><br><span class="line"><span class="comment">     * the right (increases their indices).  The new elements will appear</span></span><br><span class="line"><span class="comment">     * in the list in the order that they are returned by the</span></span><br><span class="line"><span class="comment">     * specified collection&#x27;s iterator.</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> index index at which to insert the first element from the</span></span><br><span class="line"><span class="comment">     *              specified collection</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> c collection containing elements to be added to this list</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> &lt;tt&gt;true&lt;/tt&gt; if this list changed as a result of the call</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@throws</span> IndexOutOfBoundsException &#123;<span class="doctag">@inheritDoc</span>&#125;</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@throws</span> NullPointerException if the specified collection is null</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line"><span class="comment">// 向 List 的某个位置上插入一个 List</span></span><br><span class="line"><span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">addAll</span><span class="params">(<span class="type">int</span> index, Collection&lt;? extends E&gt; c)</span> &#123;</span><br><span class="line">    rangeCheckForAdd(index); <span class="comment">// 插入索引范围检查</span></span><br><span class="line"></span><br><span class="line">    Object[] a = c.toArray();</span><br><span class="line">    <span class="type">int</span> <span class="variable">numNew</span> <span class="operator">=</span> a.length;</span><br><span class="line">    <span class="comment">// 确保内部容量</span></span><br><span class="line">    ensureCapacityInternal(size + numNew);  <span class="comment">// Increments modCount</span></span><br><span class="line"></span><br><span class="line">    <span class="type">int</span> <span class="variable">numMoved</span> <span class="operator">=</span> size - index; <span class="comment">// 要往后移动的元素个数</span></span><br><span class="line">    <span class="keyword">if</span> (numMoved &gt; <span class="number">0</span>)</span><br><span class="line">        System.arraycopy(elementData, index, elementData, index + numNew,</span><br><span class="line">                         numMoved); <span class="comment">// arraycopy 移动数组</span></span><br><span class="line"></span><br><span class="line">    System.arraycopy(a, <span class="number">0</span>, elementData, index, numNew); <span class="comment">// 将 a 数组插入到 index 位置上</span></span><br><span class="line">    size += numNew; <span class="comment">// 更新 size</span></span><br><span class="line">    <span class="keyword">return</span> numNew != <span class="number">0</span>; <span class="comment">// true or false</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>延伸：向一个空的 List 中添加一个空的 List，以下代码输出是什么？</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">List&lt;Object&gt; list = <span class="keyword">new</span> <span class="title class_">ArrayList</span>&lt;&gt;();</span><br><span class="line">List&lt;Object&gt; list2 = <span class="keyword">new</span> <span class="title class_">ArrayList</span>&lt;&gt;();</span><br><span class="line">System.out.println(list.addAll(list2));</span><br></pre></td></tr></table></figure><p>答案：<code>false</code>，添加的时候执行第一句话 <code>c.toArray()</code>，返回的 a 就是一个空数组（toArray() 方法转换的时候看的是 size 而不是数组的 length，size &#x3D; 0, length &#x3D; 10），所以 a.length &#x3D; 0，那么最后返回的就是 false。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> Object[] toArray() &#123;</span><br><span class="line">    <span class="keyword">return</span> Arrays.copyOf(elementData, size); <span class="comment">// size = 0</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> &lt;T&gt; T[] copyOf(T[] original, <span class="type">int</span> newLength) &#123; <span class="comment">// newLength = 0</span></span><br><span class="line">    <span class="keyword">return</span> (T[]) copyOf(original, newLength, original.getClass());</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> &lt;T,U&gt; T[] copyOf(U[] original, <span class="type">int</span> newLength, Class&lt;? <span class="keyword">extends</span> <span class="title class_">T</span>[]&gt; newType) &#123;</span><br><span class="line">    <span class="meta">@SuppressWarnings(&quot;unchecked&quot;)</span></span><br><span class="line">    T[] copy = ((Object)newType == (Object)Object[].class)</span><br><span class="line">        ? (T[]) <span class="keyword">new</span> <span class="title class_">Object</span>[newLength]</span><br><span class="line">        : (T[]) Array.newInstance(newType.getComponentType(), newLength);</span><br><span class="line">    System.arraycopy(original, <span class="number">0</span>, copy, <span class="number">0</span>,</span><br><span class="line">                     Math.min(original.length, newLength)); <span class="comment">// newLength = 0 </span></span><br><span class="line">    <span class="keyword">return</span> copy;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="removeRange-fromIndex-toIndex"><a href="#removeRange-fromIndex-toIndex" class="headerlink" title="removeRange(fromIndex, toIndex)"></a>removeRange(fromIndex, toIndex)</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment">     * Removes from this list all of the elements whose index is between</span></span><br><span class="line"><span class="comment">     * &#123;<span class="doctag">@code</span> fromIndex&#125;, inclusive, and &#123;<span class="doctag">@code</span> toIndex&#125;, exclusive.</span></span><br><span class="line"><span class="comment">     * Shifts any succeeding elements to the left (reduces their index).</span></span><br><span class="line"><span class="comment">     * This call shortens the list by &#123;<span class="doctag">@code</span> (toIndex - fromIndex)&#125; elements.</span></span><br><span class="line"><span class="comment">     * (If &#123;<span class="doctag">@code</span> toIndex==fromIndex&#125;, this operation has no effect.)</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@throws</span> IndexOutOfBoundsException if &#123;<span class="doctag">@code</span> fromIndex&#125; or</span></span><br><span class="line"><span class="comment">     *         &#123;<span class="doctag">@code</span> toIndex&#125; is out of range</span></span><br><span class="line"><span class="comment">     *         (&#123;<span class="doctag">@code</span> fromIndex &lt; 0 ||</span></span><br><span class="line"><span class="comment">     *          fromIndex &gt;= size() ||</span></span><br><span class="line"><span class="comment">     *          toIndex &gt; size() ||</span></span><br><span class="line"><span class="comment">     *          toIndex &lt; fromIndex&#125;)</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line"><span class="comment">// 范围删除</span></span><br><span class="line"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title function_">removeRange</span><span class="params">(<span class="type">int</span> fromIndex, <span class="type">int</span> toIndex)</span> &#123;</span><br><span class="line">    modCount++;</span><br><span class="line">    <span class="type">int</span> <span class="variable">numMoved</span> <span class="operator">=</span> size - toIndex; <span class="comment">// 要移动的元素个数</span></span><br><span class="line">    System.arraycopy(elementData, toIndex, elementData, fromIndex,</span><br><span class="line">                     numMoved); <span class="comment">// 将 [toIndex, size) 拷贝到从 fromIndex 开始</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">// clear to let GC do its work</span></span><br><span class="line">    <span class="type">int</span> <span class="variable">newSize</span> <span class="operator">=</span> size - (toIndex-fromIndex);</span><br><span class="line">    <span class="keyword">for</span> (<span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> newSize; i &lt; size; i++) &#123; <span class="comment">// 删除后面的元素</span></span><br><span class="line">        elementData[i] = <span class="literal">null</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    size = newSize; <span class="comment">// 更新 size</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="removeAll-Collection-lt-gt-c"><a href="#removeAll-Collection-lt-gt-c" class="headerlink" title="removeAll(Collection&lt;?&gt; c)"></a>removeAll(Collection&lt;?&gt; c)</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment">     * Removes from this list all of its elements that are contained in the</span></span><br><span class="line"><span class="comment">     * specified collection.</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> c collection containing elements to be removed from this list</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> &#123;<span class="doctag">@code</span> true&#125; if this list changed as a result of the call</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@throws</span> ClassCastException if the class of an element of this list</span></span><br><span class="line"><span class="comment">     *         is incompatible with the specified collection</span></span><br><span class="line"><span class="comment">     * (&lt;a href=&quot;Collection.html#optional-restrictions&quot;&gt;optional&lt;/a&gt;)</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@throws</span> NullPointerException if this list contains a null element and the</span></span><br><span class="line"><span class="comment">     *         specified collection does not permit null elements</span></span><br><span class="line"><span class="comment">     * (&lt;a href=&quot;Collection.html#optional-restrictions&quot;&gt;optional&lt;/a&gt;),</span></span><br><span class="line"><span class="comment">     *         or if the specified collection is null</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@see</span> Collection#contains(Object)</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line"><span class="comment">// 从 List 中删除集合 c 中的所有元素</span></span><br><span class="line"><span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">removeAll</span><span class="params">(Collection&lt;?&gt; c)</span> &#123;</span><br><span class="line">    Objects.requireNonNull(c); <span class="comment">// 判断是否为空，调用的是 Object 的方法</span></span><br><span class="line">    <span class="keyword">return</span> batchRemove(c, <span class="literal">false</span>); <span class="comment">// 批量删除</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// Object.class</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> &lt;T&gt; T <span class="title function_">requireNonNull</span><span class="params">(T obj)</span> &#123;</span><br><span class="line">    <span class="keyword">if</span> (obj == <span class="literal">null</span>) <span class="comment">// 只判断了是否为 null，没有判断空 List</span></span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">NullPointerException</span>();</span><br><span class="line">    <span class="keyword">return</span> obj;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">private</span> <span class="type">boolean</span> <span class="title function_">batchRemove</span><span class="params">(Collection&lt;?&gt; c, <span class="type">boolean</span> complement)</span> &#123;</span><br><span class="line">    <span class="keyword">final</span> Object[] elementData = <span class="built_in">this</span>.elementData; <span class="comment">// 复制一份 elementData</span></span><br><span class="line">    <span class="type">int</span> <span class="variable">r</span> <span class="operator">=</span> <span class="number">0</span>, w = <span class="number">0</span>; <span class="comment">// 定义两个指针</span></span><br><span class="line">    <span class="type">boolean</span> <span class="variable">modified</span> <span class="operator">=</span> <span class="literal">false</span>;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        <span class="comment">// complement = false，所以 for 循环的含义就是将不在 c 集合中的元素放到数组的前面，并且记录个数 w</span></span><br><span class="line">        <span class="keyword">for</span> (; r &lt; size; r++)</span><br><span class="line">            <span class="keyword">if</span> (c.contains(elementData[r]) == complement)</span><br><span class="line">                elementData[w++] = elementData[r];</span><br><span class="line">    &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">        <span class="comment">// Preserve behavioral compatibility with AbstractCollection,</span></span><br><span class="line">        <span class="comment">// even if c.contains() throws.</span></span><br><span class="line">        <span class="keyword">if</span> (r != size) &#123; <span class="comment">// 正常情况下上面循环执行结束 r = size</span></span><br><span class="line">            System.arraycopy(elementData, r,</span><br><span class="line">                             elementData, w,</span><br><span class="line">                             size - r);</span><br><span class="line">            w += size - r;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> (w != size) &#123; <span class="comment">// w == size 表示 elementData 全删</span></span><br><span class="line">            <span class="comment">// clear to let GC do its work</span></span><br><span class="line">            <span class="keyword">for</span> (<span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> w; i &lt; size; i++) <span class="comment">// 将 [w, size) 后面的元素全部删掉</span></span><br><span class="line">                elementData[i] = <span class="literal">null</span>;</span><br><span class="line">            modCount += size - w; <span class="comment">// 更新 modCount</span></span><br><span class="line">            size = w; <span class="comment">// 更新 size</span></span><br><span class="line">            modified = <span class="literal">true</span>; <span class="comment">// 修改成功</span></span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> modified;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="writeObject-java-io-ObjectOutputStream-s-、readObject-java-io-ObjectInputStream-s-序列化和反序列化"><a href="#writeObject-java-io-ObjectOutputStream-s-、readObject-java-io-ObjectInputStream-s-序列化和反序列化" class="headerlink" title="writeObject(java.io.ObjectOutputStream s)、readObject(java.io.ObjectInputStream s) 序列化和反序列化"></a>writeObject(java.io.ObjectOutputStream s)、readObject(java.io.ObjectInputStream s) 序列化和反序列化</h2><p>序列化：</p><ul><li>我们的 elementData <code>transient Object[] elementData; // non-private to simplify nested class access</code> 是被 transient 修饰的，所以不能被序列化，那具体是怎么序列化的呢，同时这样做的好处是什么？</li><li>看源码之后发现，是通过 for 循环 elementData 数组中的元素，对每个元素进行序列化，我不对整个数组序列化，因为 elementData 的容量通常情况下是比 size 大的，扩容的时候每次大约 1.5 倍，那么就有 1 &#x2F; 3 的空间是空的，空的数据没必要序列化。</li><li>好处：1. 不浪费序列化的内容 2. 无需考虑 null 序列化的问题，因为有的序列化方式序列化 null 会报错</li></ul><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Save the state of the &lt;tt&gt;ArrayList&lt;/tt&gt; instance to a stream (that</span></span><br><span class="line"><span class="comment"> * is, serialize it).</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@serialData</span> The length of the array backing the &lt;tt&gt;ArrayList&lt;/tt&gt;</span></span><br><span class="line"><span class="comment"> *             instance is emitted (int), followed by all of its elements</span></span><br><span class="line"><span class="comment"> *             (each an &lt;tt&gt;Object&lt;/tt&gt;) in the proper order.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title function_">writeObject</span><span class="params">(java.io.ObjectOutputStream s)</span></span><br><span class="line">    <span class="keyword">throws</span> java.io.IOException&#123;</span><br><span class="line">    <span class="comment">// Write out element count, and any hidden stuff</span></span><br><span class="line">    <span class="type">int</span> <span class="variable">expectedModCount</span> <span class="operator">=</span> modCount; <span class="comment">// 将 modCount 存一份，用于判断在 List 序列化的过程中是否有其他线程进行了修改</span></span><br><span class="line">    s.defaultWriteObject(); <span class="comment">// 对 ObjectOutputStream 做一个初始化</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">// Write out size as capacity for behavioural compatibility with clone()</span></span><br><span class="line">    s.writeInt(size); <span class="comment">// 先把 size 序列化</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">// Write out all elements in the proper order.</span></span><br><span class="line">    <span class="keyword">for</span> (<span class="type">int</span> i=<span class="number">0</span>; i&lt;size; i++) &#123; <span class="comment">// for 循环序列每个元素，这里太妙了！！！</span></span><br><span class="line">        s.writeObject(elementData[i]);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 最后判断是否有并发修改异常，如果出现异常则序列化失败</span></span><br><span class="line">    <span class="comment">// 那么如果有修改，序列化就白做了，但其实这也符合实际场景：一切对于我们的 list 的业务上的修改级别高于序列化。</span></span><br><span class="line">    <span class="keyword">if</span> (modCount != expectedModCount) &#123; </span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">ConcurrentModificationException</span>();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Reconstitute the &lt;tt&gt;ArrayList&lt;/tt&gt; instance from a stream (that is,</span></span><br><span class="line"><span class="comment"> * deserialize it).</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title function_">readObject</span><span class="params">(java.io.ObjectInputStream s)</span></span><br><span class="line">    <span class="keyword">throws</span> java.io.IOException, ClassNotFoundException &#123;</span><br><span class="line">    elementData = EMPTY_ELEMENTDATA;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// Read in size, and any hidden stuff</span></span><br><span class="line">    s.defaultReadObject();</span><br><span class="line"></span><br><span class="line">    <span class="comment">// Read in capacity</span></span><br><span class="line">    s.readInt(); <span class="comment">// ignored // 先读取 List 的大小</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (size &gt; <span class="number">0</span>) &#123; <span class="comment">// 如果有数据再反序列化</span></span><br><span class="line">        <span class="comment">// be like clone(), allocate array based upon size not capacity</span></span><br><span class="line">        <span class="type">int</span> <span class="variable">capacity</span> <span class="operator">=</span> calculateCapacity(elementData, size);</span><br><span class="line">        SharedSecrets.getJavaOISAccess().checkArray(s, Object[].class, capacity);</span><br><span class="line">        ensureCapacityInternal(size); <span class="comment">// 先保证容量</span></span><br><span class="line"></span><br><span class="line">        Object[] a = elementData;</span><br><span class="line">        <span class="comment">// Read in all elements in the proper order.</span></span><br><span class="line">        <span class="keyword">for</span> (<span class="type">int</span> i=<span class="number">0</span>; i&lt;size; i++) &#123; <span class="comment">// 每次读一个对象存到 elementData 中</span></span><br><span class="line">            a[i] = s.readObject();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="迭代器相关"><a href="#迭代器相关" class="headerlink" title="迭代器相关"></a>迭代器相关</h2><p>TODO</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;ArrayList-类属性&quot;&gt;&lt;a href=&quot;#ArrayList-类属性&quot; class=&quot;headerlink&quot; title=&quot;ArrayList 类属性&quot;&gt;&lt;/a&gt;ArrayList 类属性&lt;/h2&gt;&lt;p&gt;ArrayList 实现了 RandomAccess</summary>
      
    
    
    
    <category term="Java" scheme="https://tonngw.com/categories/Java/"/>
    
    <category term="Java 集合" scheme="https://tonngw.com/categories/Java/Java-%E9%9B%86%E5%90%88/"/>
    
    
    <category term="Java" scheme="https://tonngw.com/tags/Java/"/>
    
    <category term="Java 集合" scheme="https://tonngw.com/tags/Java-%E9%9B%86%E5%90%88/"/>
    
    <category term="ArrayList" scheme="https://tonngw.com/tags/ArrayList/"/>
    
    <category term="源码" scheme="https://tonngw.com/tags/%E6%BA%90%E7%A0%81/"/>
    
  </entry>
  
  <entry>
    <title>剑指 Offer 63. 股票的最大利润</title>
    <link href="https://tonngw.com/2022/07/09/%E5%89%91%E6%8C%87%20Offer/%E5%89%91%E6%8C%87%20Offer%2063.%20%E8%82%A1%E7%A5%A8%E7%9A%84%E6%9C%80%E5%A4%A7%E5%88%A9%E6%B6%A6/"/>
    <id>https://tonngw.com/2022/07/09/%E5%89%91%E6%8C%87%20Offer/%E5%89%91%E6%8C%87%20Offer%2063.%20%E8%82%A1%E7%A5%A8%E7%9A%84%E6%9C%80%E5%A4%A7%E5%88%A9%E6%B6%A6/</id>
    <published>2022-07-09T01:56:19.202Z</published>
    <updated>2022-07-09T02:09:24.256Z</updated>
    
    <content type="html"><![CDATA[<h3 id="题目描述"><a href="#题目描述" class="headerlink" title="题目描述"></a>题目描述</h3><p>假设把某股票的价格按照时间先后顺序存储在数组中，请问买卖该股票一次可能获得的最大利润是多少？</p><p> <strong>示例 1:</strong> </p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">输入: [7,1,5,3,6,4]</span><br><span class="line">输出: 5</span><br><span class="line">解释: 在第 2 天（股票价格 = 1）的时候买入，在第 5 天（股票价格 = 6）的时候卖出，最大利润 = 6-1 = 5 。</span><br><span class="line">     注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格。</span><br></pre></td></tr></table></figure><p> <strong>示例 2:</strong> </p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">输入: [7,6,4,3,1]</span><br><span class="line">输出: 0</span><br><span class="line">解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。</span><br></pre></td></tr></table></figure><p> <strong>限制：</strong> </p><p>$0 &lt;&#x3D; 数组长度 &lt;&#x3D; 10^5$</p><p> <strong>注意：</strong> 本题与主站 121 题相同：<a href="https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock/">https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock/</a></p><hr><h3 id="算法"><a href="#算法" class="headerlink" title="算法"></a>算法</h3><h4 id="贪心-线性扫描-O-n"><a href="#贪心-线性扫描-O-n" class="headerlink" title="(贪心,线性扫描)  $O(n)$"></a>(贪心,线性扫描)  $O(n)$</h4><p>$minv$ 表示前 $i - 1$ 天中的买入的最低价格，假设初始值为 $prices[0]$，定义变量 $res$ 表示利润<br>从第二天开始枚举，计算并更新利润 $res$，更新 $minv$</p><h4 id="时间复杂度"><a href="#时间复杂度" class="headerlink" title="时间复杂度"></a>时间复杂度</h4><p>$O(n)$</p><h4 id="空间复杂度"><a href="#空间复杂度" class="headerlink" title="空间复杂度"></a>空间复杂度</h4><p>$O(1)$</p><h3 id="代码"><a href="#代码" class="headerlink" title="代码"></a>代码</h3><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span> &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="type">int</span> <span class="title">maxProfit</span><span class="params">(vector&lt;<span class="type">int</span>&gt;&amp; prices)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (prices.<span class="built_in">empty</span>()) <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">        <span class="type">int</span> minv = prices[<span class="number">0</span>], res = <span class="number">0</span>;</span><br><span class="line">        <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i &lt; prices.<span class="built_in">size</span>(); i ++ ) &#123;</span><br><span class="line">            res = <span class="built_in">max</span>(res, prices[i] - minv);</span><br><span class="line">            minv = <span class="built_in">min</span>(minv, prices[i]);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> res;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;题目描述&quot;&gt;&lt;a href=&quot;#题目描述&quot; class=&quot;headerlink&quot; title=&quot;题目描述&quot;&gt;&lt;/a&gt;题目描述&lt;/h3&gt;&lt;p&gt;假设把某股票的价格按照时间先后顺序存储在数组中，请问买卖该股票一次可能获得的最大利润是多少？&lt;/p&gt;
&lt;p&gt; &lt;strong</summary>
      
    
    
    
    <category term="算法" scheme="https://tonngw.com/categories/%E7%AE%97%E6%B3%95/"/>
    
    <category term="剑指 Offer" scheme="https://tonngw.com/categories/%E7%AE%97%E6%B3%95/%E5%89%91%E6%8C%87-Offer/"/>
    
    
    <category term="动态规划" scheme="https://tonngw.com/tags/%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92/"/>
    
    <category term="贪心" scheme="https://tonngw.com/tags/%E8%B4%AA%E5%BF%83/"/>
    
  </entry>
  
  <entry>
    <title>剑指 Offer 60. n个骰子的点数</title>
    <link href="https://tonngw.com/2022/07/09/%E5%89%91%E6%8C%87%20Offer/%E5%89%91%E6%8C%87%20Offer%2060.%20n%E4%B8%AA%E9%AA%B0%E5%AD%90%E7%9A%84%E7%82%B9%E6%95%B0/"/>
    <id>https://tonngw.com/2022/07/09/%E5%89%91%E6%8C%87%20Offer/%E5%89%91%E6%8C%87%20Offer%2060.%20n%E4%B8%AA%E9%AA%B0%E5%AD%90%E7%9A%84%E7%82%B9%E6%95%B0/</id>
    <published>2022-07-09T01:53:53.601Z</published>
    <updated>2022-07-09T01:55:53.639Z</updated>
    
    <content type="html"><![CDATA[<h3 id="题目描述"><a href="#题目描述" class="headerlink" title="题目描述"></a>题目描述</h3><p>把n个骰子扔在地上，所有骰子朝上一面的点数之和为s。输入n，打印出s的所有可能的值出现的概率。</p><p>你需要用一个浮点数数组返回答案，其中第 i 个元素代表这 n 个骰子所能掷出的点数集合中第 i 小的那个的概率。</p><p> <strong>示例 1:</strong> </p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">输入: 1</span><br><span class="line">输出: [0.16667,0.16667,0.16667,0.16667,0.16667,0.16667]</span><br></pre></td></tr></table></figure><p> <strong>示例 2:</strong> </p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">输入: 2</span><br><span class="line">输出: [0.02778,0.05556,0.08333,0.11111,0.13889,0.16667,0.13889,0.11111,0.08333,0.05556,0.02778]</span><br></pre></td></tr></table></figure><p> <strong>限制：</strong> </p><p>$1 &lt;&#x3D; n &lt;&#x3D; 11$</p><hr><h3 id="算法"><a href="#算法" class="headerlink" title="算法"></a>算法</h3><h4 id="动态规划-O-n-2"><a href="#动态规划-O-n-2" class="headerlink" title="(动态规划)  $O(n^2)$"></a>(动态规划)  $O(n^2)$</h4><p>状态表示：<code>f[i][j]</code>，表示投 $i$ 次总和为 $j$ 的方案数<br>状态计算：按照第 $i$ 次投掷的点数为 $1，2，3，4，5，6$ 划分成六个集合<br>假设第 $i$ 次投掷的点数为 $k$，则状态转移方程为 $f[i][j] &#x3D; f[i - 1][j - k]$，对于每种情况计算方案数，最后求和。</p><p>边界：</p><ol><li>初始值：$f[0][0] &#x3D; 1$，由 $f[1][1] &#x3D; 1$ 可以推出</li><li>答案：$f[n][n]、f[n][2n]、…、f[n][6n]$，分别除以总方案数 $6^n$，最后就是每种和出现的概率值。</li></ol><h4 id="时间复杂度"><a href="#时间复杂度" class="headerlink" title="时间复杂度"></a>时间复杂度</h4><p>状态数量有 $6n^2$ 个，状态转移时间为 $O(1)$，所以时间复杂度为 $O(n^2)$。<br>状态数量 * 状态转移所需时间 &#x3D; $n^2 * O(1)$ &#x3D; $O(n^2)$。</p><h4 id="空间复杂度"><a href="#空间复杂度" class="headerlink" title="空间复杂度"></a>空间复杂度</h4><p>$O(n^2)$</p><h4 id="C-代码"><a href="#C-代码" class="headerlink" title="C++ 代码"></a>C++ 代码</h4><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span> &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function">vector&lt;<span class="type">double</span>&gt; <span class="title">dicesProbability</span><span class="params">(<span class="type">int</span> n)</span> </span>&#123;</span><br><span class="line">        vector&lt;vector&lt;<span class="type">int</span>&gt;&gt; <span class="built_in">f</span>(n + <span class="number">1</span>, <span class="built_in">vector</span>&lt;<span class="type">int</span>&gt;(<span class="number">6</span> * n + <span class="number">1</span>));</span><br><span class="line">        f[<span class="number">0</span>][<span class="number">0</span>] = <span class="number">1</span>;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i &lt;= n; i ++ ) <span class="comment">// 骰子个数</span></span><br><span class="line">            <span class="keyword">for</span> (<span class="type">int</span> j = i * <span class="number">1</span>; j &lt;= i * <span class="number">6</span>; j ++ ) <span class="comment">// 第 i 个骰子投出后可能出现的总和</span></span><br><span class="line">                <span class="keyword">for</span> (<span class="type">int</span> k = <span class="number">1</span>; k &lt;= <span class="number">6</span>; k ++ ) <span class="comment">// 按照 6 个点进行划分集合</span></span><br><span class="line">                    <span class="keyword">if</span> (k &lt;= j)</span><br><span class="line">                        f[i][j] += f[i - <span class="number">1</span>][j - k]; <span class="comment">// 状态转移</span></span><br><span class="line"></span><br><span class="line">        vector&lt;<span class="type">double</span>&gt; res;           </span><br><span class="line">        <span class="type">double</span> tot = <span class="built_in">pow</span>(<span class="number">6.0</span>, n);</span><br><span class="line">        <span class="keyword">for</span> (<span class="type">int</span> i = n; i &lt;= <span class="number">6</span> * n; i ++ ) res.<span class="built_in">push_back</span>(f[n][i] / tot); <span class="comment">// 求每种和的概率</span></span><br><span class="line">        <span class="keyword">return</span> res;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;题目描述&quot;&gt;&lt;a href=&quot;#题目描述&quot; class=&quot;headerlink&quot; title=&quot;题目描述&quot;&gt;&lt;/a&gt;题目描述&lt;/h3&gt;&lt;p&gt;把n个骰子扔在地上，所有骰子朝上一面的点数之和为s。输入n，打印出s的所有可能的值出现的概率。&lt;/p&gt;
&lt;p&gt;你需要用一个浮</summary>
      
    
    
    
    <category term="算法" scheme="https://tonngw.com/categories/%E7%AE%97%E6%B3%95/"/>
    
    <category term="剑指 Offer" scheme="https://tonngw.com/categories/%E7%AE%97%E6%B3%95/%E5%89%91%E6%8C%87-Offer/"/>
    
    
    <category term="动态规划" scheme="https://tonngw.com/tags/%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92/"/>
    
  </entry>
  
  <entry>
    <title>剑指 Offer 47. 礼物的最大价值</title>
    <link href="https://tonngw.com/2022/07/09/%E5%89%91%E6%8C%87%20Offer/%E5%89%91%E6%8C%87%20Offer%2047.%20%E7%A4%BC%E7%89%A9%E7%9A%84%E6%9C%80%E5%A4%A7%E4%BB%B7%E5%80%BC/"/>
    <id>https://tonngw.com/2022/07/09/%E5%89%91%E6%8C%87%20Offer/%E5%89%91%E6%8C%87%20Offer%2047.%20%E7%A4%BC%E7%89%A9%E7%9A%84%E6%9C%80%E5%A4%A7%E4%BB%B7%E5%80%BC/</id>
    <published>2022-07-09T01:53:17.221Z</published>
    <updated>2022-07-09T01:53:43.090Z</updated>
    
    <content type="html"><![CDATA[<h3 id="题目描述"><a href="#题目描述" class="headerlink" title="题目描述"></a>题目描述</h3><p>在一个 m*n 的棋盘的每一格都放有一个礼物，每个礼物都有一定的价值（价值大于 0）。你可以从棋盘的左上角开始拿格子里的礼物，并每次向右或者向下移动一格、直到到达棋盘的右下角。给定一个棋盘及其上面的礼物的价值，请计算你最多能拿到多少价值的礼物？</p><p> <strong>示例 1:</strong> </p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">输入: </span><br><span class="line">[</span><br><span class="line">  [1,3,1],</span><br><span class="line">  [1,5,1],</span><br><span class="line">  [4,2,1]</span><br><span class="line">]</span><br><span class="line">输出: 12</span><br><span class="line">解释: 路径 1→3→5→2→1 可以拿到最多价值的礼物</span><br></pre></td></tr></table></figure><p>提示：</p><ul><li>$0 &lt; grid.length &lt;&#x3D; 200$</li><li>$0 &lt; grid[0].length &lt;&#x3D; 200$</li></ul><hr><h3 id="算法"><a href="#算法" class="headerlink" title="算法"></a>算法</h3><h4 id="动态规划-O-n-2"><a href="#动态规划-O-n-2" class="headerlink" title="(动态规划)  $O(n^2)$"></a>(动态规划)  $O(n^2)$</h4><p>状态表示：$f[i][j]$，表示走到第 $(i, j)$ 这个格子时能拿到礼物的最大价值</p><p>状态计算：<br>每次只能向右或向下走，所以只能从左边或上边到达 $(i, j)$ </p><ol><li>左边，<code>f[i][j] = f[i][j - 1]</code></li><li>右边，<code>f[i][j] = f[i - 1][j]</code></li></ol><p>两者取 $max$</p><p>边界：<code>f[n][m]</code> 就是答案</p><h4 id="时间复杂度"><a href="#时间复杂度" class="headerlink" title="时间复杂度"></a>时间复杂度</h4><p>状态数量 $n^2$ 个，状态转移所需时间是 $O(1)$，所以总时间复杂度为 $O(n^2)$</p><h4 id="空间复杂度"><a href="#空间复杂度" class="headerlink" title="空间复杂度"></a>空间复杂度</h4><p>$O(n^2)$</p><h4 id="C-代码"><a href="#C-代码" class="headerlink" title="C++ 代码"></a>C++ 代码</h4><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span> &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="type">int</span> <span class="title">maxValue</span><span class="params">(vector&lt;vector&lt;<span class="type">int</span>&gt;&gt;&amp; grid)</span> </span>&#123;</span><br><span class="line">        <span class="comment">// n 是行 m 是列</span></span><br><span class="line">        <span class="type">int</span> n = grid.<span class="built_in">size</span>(), m = grid[<span class="number">0</span>].<span class="built_in">size</span>();</span><br><span class="line">        vector&lt;vector&lt;<span class="type">int</span>&gt;&gt; <span class="built_in">f</span>(n + <span class="number">1</span>, <span class="built_in">vector</span>&lt;<span class="type">int</span>&gt;(m + <span class="number">1</span>));</span><br><span class="line"></span><br><span class="line">        <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i &lt;= n; i ++ )</span><br><span class="line">            <span class="keyword">for</span> (<span class="type">int</span> j = <span class="number">1</span>; j &lt;= m; j ++ )</span><br><span class="line">                f[i][j] = <span class="built_in">max</span>(f[i - <span class="number">1</span>][j], f[i][j - <span class="number">1</span>]) + grid[i - <span class="number">1</span>][j - <span class="number">1</span>];</span><br><span class="line">        </span><br><span class="line">        <span class="keyword">return</span> f[n][m];</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;题目描述&quot;&gt;&lt;a href=&quot;#题目描述&quot; class=&quot;headerlink&quot; title=&quot;题目描述&quot;&gt;&lt;/a&gt;题目描述&lt;/h3&gt;&lt;p&gt;在一个 m*n 的棋盘的每一格都放有一个礼物，每个礼物都有一定的价值（价值大于 0）。你可以从棋盘的左上角开始拿格子里的礼物</summary>
      
    
    
    
    <category term="算法" scheme="https://tonngw.com/categories/%E7%AE%97%E6%B3%95/"/>
    
    <category term="剑指 Offer" scheme="https://tonngw.com/categories/%E7%AE%97%E6%B3%95/%E5%89%91%E6%8C%87-Offer/"/>
    
    
    <category term="动态规划" scheme="https://tonngw.com/tags/%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92/"/>
    
  </entry>
  
  <entry>
    <title>剑指 Offer 46. 把数字翻译成字符串</title>
    <link href="https://tonngw.com/2022/07/09/%E5%89%91%E6%8C%87%20Offer/%E5%89%91%E6%8C%87%20Offer%2046.%20%E6%8A%8A%E6%95%B0%E5%AD%97%E7%BF%BB%E8%AF%91%E6%88%90%E5%AD%97%E7%AC%A6%E4%B8%B2/"/>
    <id>https://tonngw.com/2022/07/09/%E5%89%91%E6%8C%87%20Offer/%E5%89%91%E6%8C%87%20Offer%2046.%20%E6%8A%8A%E6%95%B0%E5%AD%97%E7%BF%BB%E8%AF%91%E6%88%90%E5%AD%97%E7%AC%A6%E4%B8%B2/</id>
    <published>2022-07-09T01:52:44.915Z</published>
    <updated>2022-07-09T01:53:11.289Z</updated>
    
    <content type="html"><![CDATA[<h3 id="题目描述"><a href="#题目描述" class="headerlink" title="题目描述"></a>题目描述</h3><p>给定一个数字，我们按照如下规则把它翻译为字符串：0 翻译成 “a” ，1 翻译成 “b”，……，11 翻译成 “l”，……，25 翻译成 “z”。一个数字可能有多个翻译。请编程实现一个函数，用来计算一个数字有多少种不同的翻译方法。</p><p> <strong>示例 1:</strong> </p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">输入: 12258</span><br><span class="line">输出: 5</span><br><span class="line">解释: 12258有5种不同的翻译，分别是&quot;bccfi&quot;, &quot;bwfi&quot;, &quot;bczi&quot;, &quot;mcfi&quot;和&quot;mzi&quot;</span><br></pre></td></tr></table></figure><p> <strong>提示：</strong> </p><ul><li>$0 &lt;&#x3D; num &lt; 2^{31}$</li></ul><hr><h3 id="算法"><a href="#算法" class="headerlink" title="算法"></a>算法</h3><h4 id="动态规划-O-n"><a href="#动态规划-O-n" class="headerlink" title="(动态规划)  $O(n)$"></a>(动态规划)  $O(n)$</h4><p><strong>状态表示</strong>：$f[i]$，表示将前 $i$ 个数字翻译成字符串的方案数<br><strong>状态计算</strong></p><ol><li>将当前数字翻译成单个字母，此时 $f[i]$ 等于将前 $i - 1$ 个数字翻译成字符串的方案数，<code>f[i] = f[i - 1]</code></li><li>如果当前数字和前一个数字构成的两位数 $val$ 满足 $10 &lt;&#x3D; val &lt;&#x3D; 25$，则可以将前一个数字和当前数字翻译成一个字母，此时 $f[i]$ 等于将前 $i - 2$ 个数字翻译成字符串的方案数，<code>f[i] = f[i - 2]</code></li></ol><p><strong>边界</strong></p><ol><li><code>f[0] = 1</code>，0 个数字方案数为 1，可以通过 $f[1]$ 推出，$1$ 个数字的翻译方式只有一种（将当前数字翻译成单个字母），所以由 <code>f[i] = f[i - 1]</code> 知 <code>f[0] = 1</code>。</li><li>$f[n]$ 就是答案</li></ol><p>注意：枚举字符串时 $i$ 从 $1$ 开始，所以下标应该往前移一位，即第 $i$ 个字符 $s[i - 1]$。</p><h4 id="时间复杂度"><a href="#时间复杂度" class="headerlink" title="时间复杂度"></a>时间复杂度</h4><p>整个字符串被遍历一次，所以时间复杂度为 $O(n)$</p><h4 id="空间复杂度"><a href="#空间复杂度" class="headerlink" title="空间复杂度"></a>空间复杂度</h4><p>$O(n)$</p><h4 id="C-代码"><a href="#C-代码" class="headerlink" title="C++ 代码"></a>C++ 代码</h4><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span> &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="type">int</span> <span class="title">translateNum</span><span class="params">(<span class="type">int</span> num)</span> </span>&#123;</span><br><span class="line">        string s = <span class="built_in">to_string</span>(num);</span><br><span class="line">        <span class="type">int</span> n = s.<span class="built_in">size</span>();</span><br><span class="line">        <span class="function">vector&lt;<span class="type">int</span>&gt; <span class="title">f</span><span class="params">(n + <span class="number">1</span>)</span></span>;</span><br><span class="line">        f[<span class="number">0</span>] = <span class="number">1</span>;</span><br><span class="line">        <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i &lt;= n; i ++ ) &#123;</span><br><span class="line">            f[i] = f[i - <span class="number">1</span>];</span><br><span class="line">            <span class="keyword">if</span> (i &gt;= <span class="number">2</span>) &#123;</span><br><span class="line">                <span class="type">int</span> val = (s[i - <span class="number">2</span>] - <span class="string">&#x27;0&#x27;</span>) * <span class="number">10</span> + (s[i - <span class="number">1</span>] - <span class="string">&#x27;0&#x27;</span>);</span><br><span class="line">                <span class="keyword">if</span> (val &gt;= <span class="number">10</span> &amp;&amp; val &lt;= <span class="number">25</span>)</span><br><span class="line">                    f[i] += f[i - <span class="number">2</span>];</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> f[n];</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;题目描述&quot;&gt;&lt;a href=&quot;#题目描述&quot; class=&quot;headerlink&quot; title=&quot;题目描述&quot;&gt;&lt;/a&gt;题目描述&lt;/h3&gt;&lt;p&gt;给定一个数字，我们按照如下规则把它翻译为字符串：0 翻译成 “a” ，1 翻译成 “b”，……，11 翻译成 “l”，……，</summary>
      
    
    
    
    <category term="算法" scheme="https://tonngw.com/categories/%E7%AE%97%E6%B3%95/"/>
    
    <category term="剑指 Offer" scheme="https://tonngw.com/categories/%E7%AE%97%E6%B3%95/%E5%89%91%E6%8C%87-Offer/"/>
    
    
    <category term="动态规划" scheme="https://tonngw.com/tags/%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92/"/>
    
  </entry>
  
  <entry>
    <title>剑指 Offer 42. 连续子数组的最大和</title>
    <link href="https://tonngw.com/2022/07/09/%E5%89%91%E6%8C%87%20Offer/%E5%89%91%E6%8C%87%20Offer%2042.%20%E8%BF%9E%E7%BB%AD%E5%AD%90%E6%95%B0%E7%BB%84%E7%9A%84%E6%9C%80%E5%A4%A7%E5%92%8C/"/>
    <id>https://tonngw.com/2022/07/09/%E5%89%91%E6%8C%87%20Offer/%E5%89%91%E6%8C%87%20Offer%2042.%20%E8%BF%9E%E7%BB%AD%E5%AD%90%E6%95%B0%E7%BB%84%E7%9A%84%E6%9C%80%E5%A4%A7%E5%92%8C/</id>
    <published>2022-07-09T01:52:15.065Z</published>
    <updated>2022-07-09T01:52:36.967Z</updated>
    
    <content type="html"><![CDATA[<h3 id="题目描述"><a href="#题目描述" class="headerlink" title="题目描述"></a>题目描述</h3><p>输入一个整型数组，数组中的一个或连续多个整数组成一个子数组。求所有子数组的和的最大值。</p><p>要求时间复杂度为O(n)。</p><p> <strong>示例1:</strong> </p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">输入: nums = [-2,1,-3,4,-1,2,1,-5,4]</span><br><span class="line">输出: 6</span><br><span class="line">解释: 连续子数组 [4,-1,2,1] 的和最大，为 6。</span><br></pre></td></tr></table></figure><p> <strong>提示：</strong> </p><ul><li>$1 &lt;&#x3D; arr.length &lt;&#x3D; 10^5$</li><li>$-100 &lt;&#x3D; arr[i] &lt;&#x3D; 100$</li></ul><p>注意：本题与主站 53 题相同：<a href="https://leetcode-cn.com/problems/maximum-subarray/">https://leetcode-cn.com/problems/maximum-subarray/</a></p><hr><h3 id="算法"><a href="#算法" class="headerlink" title="算法"></a>算法</h3><h4 id="动态规划-DP-O-n"><a href="#动态规划-DP-O-n" class="headerlink" title="(动态规划,DP))  $O(n)$"></a>(动态规划,DP))  $O(n)$</h4><p>状态表示：$f[i]$ 表示以 $nums[i]$ 结尾的连续子数组的最大和<br>状态计算：</p><ol><li>包含 $nums[i]$，$f[i] &#x3D; f[i - 1] + nums[i]$</li><li>以 $nums[i]$ 开始，$f[i] &#x3D; nums[i]$</li></ol><p>$f[i]$ 两者取最大值</p><p>最后遍历 $f$ 数组取最大值</p><h4 id="时间复杂度"><a href="#时间复杂度" class="headerlink" title="时间复杂度"></a>时间复杂度</h4><p>$O(n)$</p><h4 id="空间复杂度"><a href="#空间复杂度" class="headerlink" title="空间复杂度"></a>空间复杂度</h4><p>$O(n)$</p><h4 id="C-代码"><a href="#C-代码" class="headerlink" title="C++ 代码"></a>C++ 代码</h4><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span> &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="type">int</span> <span class="title">maxSubArray</span><span class="params">(vector&lt;<span class="type">int</span>&gt;&amp; nums)</span> </span>&#123;</span><br><span class="line">        <span class="type">int</span> n = nums.<span class="built_in">size</span>();</span><br><span class="line">        <span class="function">vector&lt;<span class="type">int</span>&gt; <span class="title">f</span><span class="params">(n + <span class="number">1</span>)</span></span>;</span><br><span class="line">        <span class="type">int</span> res = INT_MIN;</span><br><span class="line">        <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i &lt;= n; i ++ ) &#123;</span><br><span class="line">            f[i] = <span class="built_in">max</span>(f[i - <span class="number">1</span>] + nums[i - <span class="number">1</span>], nums[i - <span class="number">1</span>]);</span><br><span class="line">            res = <span class="built_in">max</span>(res, f[i]);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="built_in">max</span>(res, nums[<span class="number">0</span>]);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;题目描述&quot;&gt;&lt;a href=&quot;#题目描述&quot; class=&quot;headerlink&quot; title=&quot;题目描述&quot;&gt;&lt;/a&gt;题目描述&lt;/h3&gt;&lt;p&gt;输入一个整型数组，数组中的一个或连续多个整数组成一个子数组。求所有子数组的和的最大值。&lt;/p&gt;
&lt;p&gt;要求时间复杂度为O(n</summary>
      
    
    
    
    <category term="算法" scheme="https://tonngw.com/categories/%E7%AE%97%E6%B3%95/"/>
    
    <category term="剑指 Offer" scheme="https://tonngw.com/categories/%E7%AE%97%E6%B3%95/%E5%89%91%E6%8C%87-Offer/"/>
    
    
    <category term="动态规划" scheme="https://tonngw.com/tags/%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92/"/>
    
  </entry>
  
  <entry>
    <title>剑指 Offer 19. 正则表达式匹配</title>
    <link href="https://tonngw.com/2022/07/09/%E5%89%91%E6%8C%87%20Offer/%E5%89%91%E6%8C%87%20Offer%2019.%20%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F%E5%8C%B9%E9%85%8D/"/>
    <id>https://tonngw.com/2022/07/09/%E5%89%91%E6%8C%87%20Offer/%E5%89%91%E6%8C%87%20Offer%2019.%20%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F%E5%8C%B9%E9%85%8D/</id>
    <published>2022-07-09T01:50:54.887Z</published>
    <updated>2022-07-09T01:52:04.742Z</updated>
    
    <content type="html"><![CDATA[<h3 id="题目描述"><a href="#题目描述" class="headerlink" title="题目描述"></a>题目描述</h3><p>请实现一个函数用来匹配包含$’. ‘$和$’<em>‘$的正则表达式。模式中的字符$’.’$表示任意一个字符，而$’</em>‘$表示它前面的字符可以出现任意次（含0次）。在本题中，匹配是指字符串的所有字符匹配整个模式。例如，字符串$”aaa”$与模式$”a.a”$和$”ab<em>ac</em>a”$匹配，但与$”aa.a”$和$”ab*a”$均不匹配。</p><p> <strong>示例 1:</strong> </p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">输入:</span><br><span class="line">s = &quot;aa&quot;</span><br><span class="line">p = &quot;a&quot;</span><br><span class="line">输出: false</span><br><span class="line">解释: &quot;a&quot; 无法匹配 &quot;aa&quot; 整个字符串。</span><br></pre></td></tr></table></figure><p> <strong>示例 2:</strong> </p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">输入:</span><br><span class="line">s = &quot;aa&quot;</span><br><span class="line">p = &quot;a*&quot;</span><br><span class="line">输出: true</span><br><span class="line">解释: 因为 &#x27;*&#x27; 代表可以匹配零个或多个前面的那一个元素, 在这里前面的元素就是 &#x27;a&#x27;。因此，字符串 &quot;aa&quot; 可被视为 &#x27;a&#x27; 重复了一次。</span><br></pre></td></tr></table></figure><p> <strong>示例 3:</strong> </p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">输入:</span><br><span class="line">s = &quot;ab&quot;</span><br><span class="line">p = &quot;.*&quot;</span><br><span class="line">输出: true</span><br><span class="line">解释: &quot;.*&quot; 表示可匹配零个或多个（&#x27;*&#x27;）任意字符（&#x27;.&#x27;）。</span><br></pre></td></tr></table></figure><p> <strong>示例 4:</strong> </p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">输入:</span><br><span class="line">s = &quot;aab&quot;</span><br><span class="line">p = &quot;c*a*b&quot;</span><br><span class="line">输出: true</span><br><span class="line">解释: 因为 &#x27;*&#x27; 表示零个或多个，这里 &#x27;c&#x27; 为 0 个, &#x27;a&#x27; 被重复一次。因此可以匹配字符串 &quot;aab&quot;。</span><br></pre></td></tr></table></figure><p> <strong>示例 5:</strong> </p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">输入:</span><br><span class="line">s = &quot;mississippi&quot;</span><br><span class="line">p = &quot;mis*is*p*.&quot;</span><br><span class="line">输出: false</span><br></pre></td></tr></table></figure><ul><li>$s$ 可能为空，且只包含从 $a-z$ 的小写字母。</li><li>$p$ 可能为空，且只包含从 $a-z$ 的小写字母以及字符 $.$ 和 $<em>$，无连续的 $’</em>‘$。</li></ul><p>注意：本题与主站 10 题相同：<a href="https://leetcode-cn.com/problems/regular-expression-matching/">https://leetcode-cn.com/problems/regular-expression-matching/</a></p><hr><h3 id="算法"><a href="#算法" class="headerlink" title="算法"></a>算法</h3><h4 id="动态规划-O-n-2"><a href="#动态规划-O-n-2" class="headerlink" title="(动态规划)  $O(n^2)$"></a>(动态规划)  $O(n^2)$</h4><p>状态表示：$s$ 的前 $i$ 个字母 <code>s[1~i]</code> 和 $p$ 的前 $j$ 个字母是否匹配（下标从 $1$ 开始比较方便  ）<br>状态计算：根据 <code>p[j + 1]</code> 是否为 <code>*</code> 分情况讨论，因为如果 <code>p[j +1] = *</code> 时那么 <code>p[j-j+1]</code> 是一个整体。（$*$ 表示前面的一个字符可以出现任意多次）</p><p>特判：如果 $p[j + 1]$ 是 $*$ 的话那么不处理当前字符 $p[j]$，<code>continue</code>，将它们作为一个整体处理，</p><ol><li>如果当前字符 $p[j]$ 不是 <code>*</code>，则 <code>f[i][j] = true</code> 当且仅当 <code>s[1~i-1]</code> 和 <code>p[1~j-1]</code> 匹配且 s[i] 和 p[j] 匹配（或者 <code>p[j] == &#39;.&#39;</code> 也是匹配的）<code>f[i][j] = f[i - 1][j - 1] &amp;&amp; (s[i] == p[j] || p[j] == &#39;.&#39;);</code></li><li>如果当前字符 $p[j]$ 是 <code>*</code>，则遍历 $*$ 号前面的字符出现从 $0$ 次到任意多次与 $s[i]$ 进行匹配。<code>f[i][j] = f[i][j - 2] || (i &amp;&amp; f[i - 1][j] &amp;&amp; (s[i] == p[j - 1] || p[j - 1] == &#39;.&#39;));</code>，这里经过了状态转移优化，这个优化类似于完全背包优化，都是用 <code>f[i - 1][j]</code> 替换了除出现 $0$ 次以外的循环遍历。</li></ol><h4 id="时间复杂度"><a href="#时间复杂度" class="headerlink" title="时间复杂度"></a>时间复杂度</h4><p>$O(n^2)$ </p><h4 id="空间复杂度"><a href="#空间复杂度" class="headerlink" title="空间复杂度"></a>空间复杂度</h4><p>$O(n^2)$ </p><h4 id="C-代码"><a href="#C-代码" class="headerlink" title="C++ 代码"></a>C++ 代码</h4><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span> &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="type">bool</span> <span class="title">isMatch</span><span class="params">(string s, string p)</span> </span>&#123;</span><br><span class="line">        <span class="type">int</span> n = s.<span class="built_in">size</span>(), m = p.<span class="built_in">size</span>();</span><br><span class="line">        s = <span class="string">&#x27; &#x27;</span> + s, p = <span class="string">&#x27; &#x27;</span> + p;</span><br><span class="line">        vector&lt;vector&lt;<span class="type">bool</span>&gt;&gt; <span class="built_in">f</span>(n + <span class="number">1</span>, <span class="built_in">vector</span>&lt;<span class="type">bool</span>&gt;(m + <span class="number">1</span>));</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 两个空串匹配</span></span><br><span class="line">        f[<span class="number">0</span>][<span class="number">0</span>] = <span class="literal">true</span>;</span><br><span class="line">        <span class="comment">// i 从 0 开始，因为 s[i] 是空串的时候可能会和 p[j] 匹配成功（当 j + 1 是 *，可以表示 p[j] 出现 0 次，此时两个串匹配成功）</span></span><br><span class="line">        <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i &lt;= n; i ++ ) &#123;</span><br><span class="line">            <span class="comment">// j 从 1 开始，i = 0、j = 0 已经初始化过了，而对于 i != 0、j = 0，空串都不会匹配成功</span></span><br><span class="line">            <span class="keyword">for</span> (<span class="type">int</span> j = <span class="number">1</span>; j &lt;= m; j ++ ) &#123;</span><br><span class="line">                <span class="comment">// 如果 p[j] 的下一个字符是 * 就不处理当前字符，因为 p[j] 和 * 在一块才能整体才能表示一个含义</span></span><br><span class="line">                <span class="keyword">if</span> (j + <span class="number">1</span> &lt;= m &amp;&amp; p[j + <span class="number">1</span>] == <span class="string">&#x27;*&#x27;</span>) <span class="keyword">continue</span>;</span><br><span class="line">                <span class="comment">// p[j + 1] 不是 *，那就看 f[i - 1][j - 1] 是否匹配且当前字符是否匹配</span></span><br><span class="line">                <span class="keyword">if</span> (i &amp;&amp; p[j] != <span class="string">&#x27;*&#x27;</span>) &#123;</span><br><span class="line">                    f[i][j] = f[i - <span class="number">1</span>][j - <span class="number">1</span>] &amp;&amp; (s[i] == p[j] || p[j] == <span class="string">&#x27;.&#x27;</span>);</span><br><span class="line">                &#125; <span class="keyword">else</span> <span class="keyword">if</span> (p[j] == <span class="string">&#x27;*&#x27;</span>) &#123;</span><br><span class="line">                    <span class="comment">// 与 0 个第 j - 1 个字母匹配 || 【1 个 || 2 个 ... 进行了状态转移优化（完全背包优化）】</span></span><br><span class="line">                    f[i][j] = f[i][j - <span class="number">2</span>] || (i &amp;&amp; f[i - <span class="number">1</span>][j] &amp;&amp; (s[i] == p[j - <span class="number">1</span>] || p[j - <span class="number">1</span>] == <span class="string">&#x27;.&#x27;</span>));</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> f[n][m];</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;题目描述&quot;&gt;&lt;a href=&quot;#题目描述&quot; class=&quot;headerlink&quot; title=&quot;题目描述&quot;&gt;&lt;/a&gt;题目描述&lt;/h3&gt;&lt;p&gt;请实现一个函数用来匹配包含$’. ‘$和$’&lt;em&gt;‘$的正则表达式。模式中的字符$’.’$表示任意一个字符，而$’&lt;/em</summary>
      
    
    
    
    <category term="算法" scheme="https://tonngw.com/categories/%E7%AE%97%E6%B3%95/"/>
    
    <category term="剑指 Offer" scheme="https://tonngw.com/categories/%E7%AE%97%E6%B3%95/%E5%89%91%E6%8C%87-Offer/"/>
    
    
    <category term="动态规划" scheme="https://tonngw.com/tags/%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92/"/>
    
  </entry>
  
  <entry>
    <title>剑指 Offer 38. 字符串的排列</title>
    <link href="https://tonngw.com/2022/07/09/%E5%89%91%E6%8C%87%20Offer/%E5%89%91%E6%8C%87%20Offer%2038.%20%E5%AD%97%E7%AC%A6%E4%B8%B2%E7%9A%84%E6%8E%92%E5%88%97/"/>
    <id>https://tonngw.com/2022/07/09/%E5%89%91%E6%8C%87%20Offer/%E5%89%91%E6%8C%87%20Offer%2038.%20%E5%AD%97%E7%AC%A6%E4%B8%B2%E7%9A%84%E6%8E%92%E5%88%97/</id>
    <published>2022-07-09T01:49:24.382Z</published>
    <updated>2022-07-09T01:50:36.168Z</updated>
    
    <content type="html"><![CDATA[<h3 id="题目描述"><a href="#题目描述" class="headerlink" title="题目描述"></a>题目描述</h3><p>输入一个字符串，打印出该字符串中字符的所有排列。</p><p>你可以以任意顺序返回这个字符串数组，但里面不能有重复元素。</p><p> <strong>示例:</strong> </p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">输入：s = &quot;abc&quot;</span><br><span class="line">输出：[&quot;abc&quot;,&quot;acb&quot;,&quot;bac&quot;,&quot;bca&quot;,&quot;cab&quot;,&quot;cba&quot;]</span><br></pre></td></tr></table></figure><p> <strong>限制：</strong> </p><p>$1 &lt;&#x3D; s 的长度 &lt;&#x3D; 8$</p><hr><h3 id="算法"><a href="#算法" class="headerlink" title="算法"></a>算法</h3><h4 id="回溯-O-n-n"><a href="#回溯-O-n-n" class="headerlink" title="(回溯)  $O(n! * n)$"></a>(回溯)  $O(n! * n)$</h4><p>和 <a href="https://leetcode-cn.com/problems/permutations/solution/46-quan-pai-lie-by-tonngw-08i3/">46. 全排列</a> 的唯一区别就是这道题目存在重复答案，所以需要去重，去重的思路首先将数组排序，让相同的数相邻，如果当前数等于前一个数且前一个数没有被使用过，则跳过当前数，继续查找下一个要放在当前位置上的数，始终保证排列后的序列相同数的相对顺序不变。</p><h4 id="时间复杂度"><a href="#时间复杂度" class="headerlink" title="时间复杂度"></a>时间复杂度</h4><p>全排列总共有 $A^n_n$ 种方案，即 $n!$，记录每种方案需要 $O(n)$ 的时间，所以总时间复杂度为 $O(n!*n)$。</p><h4 id="空间复杂度"><a href="#空间复杂度" class="headerlink" title="空间复杂度"></a>空间复杂度</h4><p>额外空间复杂度 $O(n)$</p><h4 id="C-代码"><a href="#C-代码" class="headerlink" title="C++ 代码"></a>C++ 代码</h4><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span> &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    vector&lt;string&gt; res;</span><br><span class="line">    string path;</span><br><span class="line">    vector&lt;<span class="type">bool</span>&gt; st;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="type">void</span> <span class="title">dfs</span><span class="params">(<span class="type">int</span> u, string&amp; s)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (u == s.<span class="built_in">size</span>()) &#123;</span><br><span class="line">            res.<span class="built_in">push_back</span>(path);</span><br><span class="line">            <span class="keyword">return</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i &lt; s.<span class="built_in">size</span>(); i ++ ) &#123;</span><br><span class="line">            <span class="comment">// 如果当前数等于前一个数且前一个数没用过，则使用前一个数</span></span><br><span class="line">            <span class="keyword">if</span> (i &amp;&amp; !st[i - <span class="number">1</span>] &amp;&amp; s[i - <span class="number">1</span>] == s[i]) <span class="keyword">continue</span>;</span><br><span class="line">            <span class="keyword">if</span> (!st[i]) &#123;</span><br><span class="line">                path += s[i];</span><br><span class="line">                st[i] = <span class="literal">true</span>;</span><br><span class="line">                <span class="built_in">dfs</span>(u + <span class="number">1</span>, s);</span><br><span class="line">                st[i] = <span class="literal">false</span>;</span><br><span class="line">                path.<span class="built_in">pop_back</span>();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function">vector&lt;string&gt; <span class="title">permutation</span><span class="params">(string s)</span> </span>&#123;</span><br><span class="line">        <span class="built_in">sort</span>(s.<span class="built_in">begin</span>(), s.<span class="built_in">end</span>());</span><br><span class="line">        st = <span class="built_in">vector</span>&lt;<span class="type">bool</span>&gt;(s.<span class="built_in">size</span>());</span><br><span class="line">        <span class="built_in">dfs</span>(<span class="number">0</span>, s);</span><br><span class="line">        <span class="keyword">return</span> res;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;题目描述&quot;&gt;&lt;a href=&quot;#题目描述&quot; class=&quot;headerlink&quot; title=&quot;题目描述&quot;&gt;&lt;/a&gt;题目描述&lt;/h3&gt;&lt;p&gt;输入一个字符串，打印出该字符串中字符的所有排列。&lt;/p&gt;
&lt;p&gt;你可以以任意顺序返回这个字符串数组，但里面不能有重复元素。&lt;</summary>
      
    
    
    
    <category term="算法" scheme="https://tonngw.com/categories/%E7%AE%97%E6%B3%95/"/>
    
    <category term="剑指 Offer" scheme="https://tonngw.com/categories/%E7%AE%97%E6%B3%95/%E5%89%91%E6%8C%87-Offer/"/>
    
    
    <category term="搜索" scheme="https://tonngw.com/tags/%E6%90%9C%E7%B4%A2/"/>
    
    <category term="DFS" scheme="https://tonngw.com/tags/DFS/"/>
    
    <category term="回溯" scheme="https://tonngw.com/tags/%E5%9B%9E%E6%BA%AF/"/>
    
  </entry>
  
  <entry>
    <title>剑指 Offer 13. 机器人的运动范围</title>
    <link href="https://tonngw.com/2022/07/09/%E5%89%91%E6%8C%87%20Offer/%E5%89%91%E6%8C%87%20Offer%2013.%20%E6%9C%BA%E5%99%A8%E4%BA%BA%E7%9A%84%E8%BF%90%E5%8A%A8%E8%8C%83%E5%9B%B4/"/>
    <id>https://tonngw.com/2022/07/09/%E5%89%91%E6%8C%87%20Offer/%E5%89%91%E6%8C%87%20Offer%2013.%20%E6%9C%BA%E5%99%A8%E4%BA%BA%E7%9A%84%E8%BF%90%E5%8A%A8%E8%8C%83%E5%9B%B4/</id>
    <published>2022-07-09T01:48:24.912Z</published>
    <updated>2022-07-09T01:49:10.173Z</updated>
    
    <content type="html"><![CDATA[<h3 id="题目描述"><a href="#题目描述" class="headerlink" title="题目描述"></a>题目描述</h3><p>地上有一个m行n列的方格，从坐标 $[0,0]$ 到坐标 $[m-1,n-1]$ 。一个机器人从坐标 $[0, 0]$ 的格子开始移动，它每次可以向左、右、上、下移动一格（不能移动到方格外），也不能进入行坐标和列坐标的数位之和大于k的格子。例如，当k为18时，机器人能够进入方格 [35, 37] ，因为3+5+3+7&#x3D;18。但它不能进入方格 [35, 38]，因为3+5+3+8&#x3D;19。请问该机器人能够到达多少个格子？</p><p> <strong>示例 1：</strong> </p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">输入：m = 2, n = 3, k = 1</span><br><span class="line">输出：3</span><br></pre></td></tr></table></figure><p> <strong>示例 2：</strong> </p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">输入：m = 3, n = 1, k = 0</span><br><span class="line">输出：1</span><br></pre></td></tr></table></figure><p> <strong>提示：</strong> </p><ul><li>$1 &lt;&#x3D; n,m &lt;&#x3D; 100$</li><li>$0 &lt;&#x3D; k &lt;&#x3D; 20$</li></ul><hr><h3 id="算法"><a href="#算法" class="headerlink" title="算法"></a>算法</h3><h4 id="BFS-O-nm"><a href="#BFS-O-nm" class="headerlink" title="(BFS))  $O(nm)$"></a>(BFS))  $O(nm)$</h4><p>$BFS$ 搜索所有可以到达的格子，初始状态将起点加入队列中，如果队列不为空，则弹出队头作为新的起点，如果当前点可以走，则枚举四个方向扩展下一层，将所有没有越界的点加入队列中，直到队列为空所有点就都被遍历完了。</p><p>哪些点可以走呢？</p><ol><li>没有走过的点</li><li>当前点横纵坐标每位之和小于等于 $k$</li></ol><h4 id="时间复杂度"><a href="#时间复杂度" class="headerlink" title="时间复杂度"></a>时间复杂度</h4><p>最坏情况下每个点都会被遍历一次，所以时间复杂度为 $O(nm)$。</p><h4 id="空间复杂度"><a href="#空间复杂度" class="headerlink" title="空间复杂度"></a>空间复杂度</h4><p>$O(nm)$</p><h4 id="C-代码"><a href="#C-代码" class="headerlink" title="C++ 代码"></a>C++ 代码</h4><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span> &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="type">int</span> <span class="title">get</span><span class="params">(<span class="type">int</span> x)</span> </span>&#123;</span><br><span class="line">        <span class="type">int</span> res = <span class="number">0</span>;</span><br><span class="line">        <span class="keyword">while</span> (x) &#123;</span><br><span class="line">            res += x % <span class="number">10</span>;</span><br><span class="line">            x /= <span class="number">10</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> res;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="type">int</span> <span class="title">movingCount</span><span class="params">(<span class="type">int</span> m, <span class="type">int</span> n, <span class="type">int</span> k)</span> </span>&#123;</span><br><span class="line">        vector&lt;vector&lt;<span class="type">bool</span>&gt;&gt; <span class="built_in">st</span>(m, <span class="built_in">vector</span>&lt;<span class="type">bool</span>&gt;(n, <span class="literal">false</span>));</span><br><span class="line">        <span class="type">int</span> res = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">        queue&lt;pair&lt;<span class="type">int</span>, <span class="type">int</span>&gt;&gt; q;</span><br><span class="line">        q.<span class="built_in">push</span>(&#123;<span class="number">0</span>, <span class="number">0</span>&#125;);</span><br><span class="line"></span><br><span class="line">        <span class="type">int</span> dx[<span class="number">4</span>] = &#123;<span class="number">-1</span>, <span class="number">0</span>, <span class="number">1</span>, <span class="number">0</span>&#125;, dy[<span class="number">4</span>] = &#123;<span class="number">0</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">-1</span>&#125;;</span><br><span class="line">        <span class="keyword">while</span> (q.<span class="built_in">size</span>()) &#123;</span><br><span class="line">            <span class="keyword">auto</span> t = q.<span class="built_in">front</span>();</span><br><span class="line">            q.<span class="built_in">pop</span>();</span><br><span class="line">            </span><br><span class="line">            <span class="type">int</span> x = t.first, y = t.second;</span><br><span class="line">            <span class="keyword">if</span> (st[x][y] || <span class="built_in">get</span>(x) + <span class="built_in">get</span>(y) &gt; k) <span class="keyword">continue</span>;</span><br><span class="line"></span><br><span class="line">            res ++ ;</span><br><span class="line">            st[x][y] = <span class="literal">true</span>;</span><br><span class="line"></span><br><span class="line">            <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i &lt; <span class="number">4</span>; i ++ ) &#123;</span><br><span class="line">                <span class="type">int</span> a = x + dx[i], b = y + dy[i];</span><br><span class="line">                <span class="keyword">if</span> (a &lt; <span class="number">0</span> || a &gt;= m || b &lt; <span class="number">0</span> || b &gt;= n) <span class="keyword">continue</span>;</span><br><span class="line">                q.<span class="built_in">push</span>(&#123;a, b&#125;);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> res;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;题目描述&quot;&gt;&lt;a href=&quot;#题目描述&quot; class=&quot;headerlink&quot; title=&quot;题目描述&quot;&gt;&lt;/a&gt;题目描述&lt;/h3&gt;&lt;p&gt;地上有一个m行n列的方格，从坐标 $[0,0]$ 到坐标 $[m-1,n-1]$ 。一个机器人从坐标 $[0, 0]$ 的格</summary>
      
    
    
    
    <category term="算法" scheme="https://tonngw.com/categories/%E7%AE%97%E6%B3%95/"/>
    
    <category term="剑指 Offer" scheme="https://tonngw.com/categories/%E7%AE%97%E6%B3%95/%E5%89%91%E6%8C%87-Offer/"/>
    
    
    <category term="搜索" scheme="https://tonngw.com/tags/%E6%90%9C%E7%B4%A2/"/>
    
    <category term="BFS" scheme="https://tonngw.com/tags/BFS/"/>
    
  </entry>
  
  <entry>
    <title>剑指 Offer 58 - I. 翻转单词顺序</title>
    <link href="https://tonngw.com/2022/07/09/%E5%89%91%E6%8C%87%20Offer/%E5%89%91%E6%8C%87%20Offer%2058%20-%20I.%20%E7%BF%BB%E8%BD%AC%E5%8D%95%E8%AF%8D%E9%A1%BA%E5%BA%8F/"/>
    <id>https://tonngw.com/2022/07/09/%E5%89%91%E6%8C%87%20Offer/%E5%89%91%E6%8C%87%20Offer%2058%20-%20I.%20%E7%BF%BB%E8%BD%AC%E5%8D%95%E8%AF%8D%E9%A1%BA%E5%BA%8F/</id>
    <published>2022-07-09T01:41:52.878Z</published>
    <updated>2022-07-09T01:48:06.001Z</updated>
    
    <content type="html"><![CDATA[<h3 id="题目描述"><a href="#题目描述" class="headerlink" title="题目描述"></a>题目描述</h3><p>输入一个英文句子，翻转句子中单词的顺序，但单词内字符的顺序不变。为简单起见，标点符号和普通字母一样处理。例如输入字符串”I am a student. “，则输出”student. a am I”。</p><p> <strong>示例 1：</strong> </p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">输入: &quot;the sky is blue&quot;</span><br><span class="line">输出: &quot;blue is sky the&quot;</span><br></pre></td></tr></table></figure><p> <strong>示例 2：</strong> </p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">输入: &quot;  hello world!  &quot;</span><br><span class="line">输出: &quot;world! hello&quot;</span><br><span class="line">解释: 输入字符串可以在前面或者后面包含多余的空格，但是反转后的字符不能包括。</span><br></pre></td></tr></table></figure><p> <strong>示例 3：</strong> </p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">输入: &quot;a good   example&quot;</span><br><span class="line">输出: &quot;example good a&quot;</span><br><span class="line">解释: 如果两个单词间有多余的空格，将反转后单词间的空格减少到只含一个。</span><br></pre></td></tr></table></figure><p> <strong>说明：</strong> </p><ul><li>无空格字符构成一个单词。</li><li>输入字符串可以在前面或者后面包含多余的空格，但是反转后的字符不能包括。</li><li>如果两个单词间有多余的空格，将反转后单词间的空格减少到只含一个。</li></ul><p> <strong>注意：</strong> 本题与主站 151 题相同：<a href="https://leetcode-cn.com/problems/reverse-words-in-a-string/">https://leetcode-cn.com/problems/reverse-words-in-a-string/</a></p><p> <strong>注意：</strong> 此题对比原题有改动</p><hr><h3 id="算法"><a href="#算法" class="headerlink" title="算法"></a>算法</h3><h4 id="字符串翻转-O-n"><a href="#字符串翻转-O-n" class="headerlink" title="(字符串翻转)  $O(n)$"></a>(字符串翻转)  $O(n)$</h4><ol><li>使用双指针算法先翻转每个单词</li><li>然后翻转整个字符串</li></ol><p>但在字符串的开头、中间、结尾都可能会有空格，我们需要把这三部分多余的空格去掉，只保留每个单词之间的空格。而且题目要求使用 $O(1)$ 的空间完成，所以只能复用字符串，用一个指针 $k$ 从前往后存储有效的字符部分，翻转结束后 $k$ 后面多余的字符都删掉。</p><p>$[i, j]$ 单词部分放到 $[k, t]$ 位置上</p><h4 id="时间复杂度"><a href="#时间复杂度" class="headerlink" title="时间复杂度"></a>时间复杂度</h4><p>整个字符串需要被扫描两遍，所以时间复杂度为 $O(n)$</p><h4 id="空间复杂度"><a href="#空间复杂度" class="headerlink" title="空间复杂度"></a>空间复杂度</h4><p>$O(1)$</p><h3 id="代码"><a href="#代码" class="headerlink" title="代码"></a>代码</h3><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span> &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function">string <span class="title">reverseWords</span><span class="params">(string s)</span> </span>&#123;</span><br><span class="line">        <span class="type">int</span> k = <span class="number">0</span>;</span><br><span class="line">        <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i &lt; s.<span class="built_in">size</span>(); i ++ ) &#123;</span><br><span class="line">            <span class="keyword">if</span> (s[i] == <span class="string">&#x27; &#x27;</span>) <span class="keyword">continue</span>;</span><br><span class="line">            <span class="comment">// k 指向单词的开头，t 指向这个单词末尾的下一个位置</span></span><br><span class="line">            <span class="type">int</span> j = i, t = k;</span><br><span class="line">            <span class="keyword">while</span> (j &lt; s.<span class="built_in">size</span>() &amp;&amp; s[j] != <span class="string">&#x27; &#x27;</span>) s[t ++ ] = s[j ++ ];</span><br><span class="line">            <span class="comment">// 翻转单词 $s[k]~s[t - 1]$</span></span><br><span class="line">            <span class="built_in">reverse</span>(s.<span class="built_in">begin</span>() + k, s.<span class="built_in">begin</span>() + t);</span><br><span class="line">            s[t ++ ] = <span class="string">&#x27; &#x27;</span>;</span><br><span class="line">            i = j, k = t;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// 翻转结束后 k 指向的是下一个单词的开头，现在让它指向前一个位置的空格</span></span><br><span class="line">        <span class="keyword">if</span> (k) k -- ;</span><br><span class="line">        <span class="comment">// 删除空格以及下标 k 后面的字符</span></span><br><span class="line">        s.<span class="built_in">erase</span>(s.<span class="built_in">begin</span>() + k, s.<span class="built_in">end</span>());</span><br><span class="line">        <span class="built_in">reverse</span>(s.<span class="built_in">begin</span>(), s.<span class="built_in">end</span>());</span><br><span class="line">        <span class="keyword">return</span> s;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;题目描述&quot;&gt;&lt;a href=&quot;#题目描述&quot; class=&quot;headerlink&quot; title=&quot;题目描述&quot;&gt;&lt;/a&gt;题目描述&lt;/h3&gt;&lt;p&gt;输入一个英文句子，翻转句子中单词的顺序，但单词内字符的顺序不变。为简单起见，标点符号和普通字母一样处理。例如输入字符串”I </summary>
      
    
    
    
    <category term="算法" scheme="https://tonngw.com/categories/%E7%AE%97%E6%B3%95/"/>
    
    <category term="剑指 Offer" scheme="https://tonngw.com/categories/%E7%AE%97%E6%B3%95/%E5%89%91%E6%8C%87-Offer/"/>
    
    
    <category term="双指针" scheme="https://tonngw.com/tags/%E5%8F%8C%E6%8C%87%E9%92%88/"/>
    
    <category term="字符串" scheme="https://tonngw.com/tags/%E5%AD%97%E7%AC%A6%E4%B8%B2/"/>
    
  </entry>
  
  <entry>
    <title>剑指 Offer 48. 最长不含重复字符的子字符串</title>
    <link href="https://tonngw.com/2022/07/09/%E5%89%91%E6%8C%87%20Offer/%E5%89%91%E6%8C%87%20Offer%2057%20-%20II.%20%E5%92%8C%E4%B8%BAs%E7%9A%84%E8%BF%9E%E7%BB%AD%E6%AD%A3%E6%95%B0%E5%BA%8F%E5%88%97/"/>
    <id>https://tonngw.com/2022/07/09/%E5%89%91%E6%8C%87%20Offer/%E5%89%91%E6%8C%87%20Offer%2057%20-%20II.%20%E5%92%8C%E4%B8%BAs%E7%9A%84%E8%BF%9E%E7%BB%AD%E6%AD%A3%E6%95%B0%E5%BA%8F%E5%88%97/</id>
    <published>2022-07-09T01:40:51.626Z</published>
    <updated>2022-07-09T01:40:47.066Z</updated>
    
    <content type="html"><![CDATA[<h3 id="题目描述"><a href="#题目描述" class="headerlink" title="题目描述"></a>题目描述</h3><p>请从字符串中找出一个最长的不包含重复字符的子字符串，计算该最长子字符串的长度。</p><p> <strong>示例 1:</strong> </p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">输入: &quot;abcabcbb&quot;</span><br><span class="line">输出: 3 </span><br><span class="line">解释: 因为无重复字符的最长子串是 &quot;abc&quot;，所以其长度为 3。</span><br></pre></td></tr></table></figure><p> <strong>示例 2:</strong> </p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">输入: &quot;bbbbb&quot;</span><br><span class="line">输出: 1</span><br><span class="line">解释: 因为无重复字符的最长子串是 &quot;b&quot;，所以其长度为 1。</span><br></pre></td></tr></table></figure><p> <strong>示例 3:</strong> </p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">输入: &quot;pwwkew&quot;</span><br><span class="line">输出: 3</span><br><span class="line">解释: 因为无重复字符的最长子串是 &quot;wke&quot;，所以其长度为 3。</span><br><span class="line">     请注意，你的答案必须是 子串 的长度，&quot;pwke&quot; 是一个子序列，不是子串。</span><br></pre></td></tr></table></figure><p>提示：</p><ul><li>$s.length &lt;&#x3D; 40000$</li></ul><p>注意：本题与主站 3 题相同：<a href="https://leetcode-cn.com/problems/longest-substring-without-repeating-characters/">https://leetcode-cn.com/problems/longest-substring-without-repeating-characters/</a></p><hr><h3 id="算法"><a href="#算法" class="headerlink" title="算法"></a>算法</h3><h4 id="哈希表，双指针算法-O-n"><a href="#哈希表，双指针算法-O-n" class="headerlink" title="(哈希表，双指针算法)  $O(n)$"></a>(哈希表，双指针算法)  $O(n)$</h4><p>用哈希表存储每个字符出现的次数，且保证区间 $[i, j]$ 内没有重复元素，每个字符只出现一次；$res$ 记录答案。</p><p>双指针扫描字符串</p><ol><li>每次将 $s[i]$ 加入到哈希表中</li><li>如果 $s[i]$ 出现的次数超过 1，说明在 $[j, i - 1]$ 中有重复元素，此时移动 $j$ 指针直到区间 $[j, i]$ 中没有重复元素为止。</li><li>计算区间长度即当前不含重复字符的字符串的长度，更新 res，<code>res = max(res, i - j + 1)</code>。</li></ol><h4 id="时间复杂度"><a href="#时间复杂度" class="headerlink" title="时间复杂度"></a>时间复杂度</h4><p>$i, j$ 最多扫描一遍字符串，所以时间复杂度为 $O(n)$</p><h4 id="空间复杂度"><a href="#空间复杂度" class="headerlink" title="空间复杂度"></a>空间复杂度</h4><p>$O(n)$</p><h4 id="C-代码"><a href="#C-代码" class="headerlink" title="C++ 代码"></a>C++ 代码</h4><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span> &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="type">int</span> <span class="title">lengthOfLongestSubstring</span><span class="params">(string s)</span> </span>&#123;</span><br><span class="line">        unordered_map&lt;<span class="type">int</span>, <span class="type">int</span>&gt; cnt;</span><br><span class="line">        <span class="type">int</span> res = <span class="number">0</span>;</span><br><span class="line">        <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>, j = <span class="number">0</span>; i &lt; s.<span class="built_in">size</span>(); i ++ ) &#123;</span><br><span class="line">            cnt[s[i]] ++ ;</span><br><span class="line">            <span class="keyword">while</span> (cnt[s[i]] &gt; <span class="number">1</span>) cnt[s[j ++ ]] -- ;</span><br><span class="line">            res = <span class="built_in">max</span>(res, i - j + <span class="number">1</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> res;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;题目描述&quot;&gt;&lt;a href=&quot;#题目描述&quot; class=&quot;headerlink&quot; title=&quot;题目描述&quot;&gt;&lt;/a&gt;题目描述&lt;/h3&gt;&lt;p&gt;请从字符串中找出一个最长的不包含重复字符的子字符串，计算该最长子字符串的长度。&lt;/p&gt;
&lt;p&gt; &lt;strong&gt;示例 1:&lt;</summary>
      
    
    
    
    <category term="算法" scheme="https://tonngw.com/categories/%E7%AE%97%E6%B3%95/"/>
    
    <category term="剑指 Offer" scheme="https://tonngw.com/categories/%E7%AE%97%E6%B3%95/%E5%89%91%E6%8C%87-Offer/"/>
    
    
    <category term="双指针" scheme="https://tonngw.com/tags/%E5%8F%8C%E6%8C%87%E9%92%88/"/>
    
    <category term="哈希表" scheme="https://tonngw.com/tags/%E5%93%88%E5%B8%8C%E8%A1%A8/"/>
    
  </entry>
  
  <entry>
    <title>剑指 Offer 48. 最长不含重复字符的子字符串</title>
    <link href="https://tonngw.com/2022/07/09/%E5%89%91%E6%8C%87%20Offer/%E5%89%91%E6%8C%87%20Offer%2048.%20%E6%9C%80%E9%95%BF%E4%B8%8D%E5%90%AB%E9%87%8D%E5%A4%8D%E5%AD%97%E7%AC%A6%E7%9A%84%E5%AD%90%E5%AD%97%E7%AC%A6%E4%B8%B2/"/>
    <id>https://tonngw.com/2022/07/09/%E5%89%91%E6%8C%87%20Offer/%E5%89%91%E6%8C%87%20Offer%2048.%20%E6%9C%80%E9%95%BF%E4%B8%8D%E5%90%AB%E9%87%8D%E5%A4%8D%E5%AD%97%E7%AC%A6%E7%9A%84%E5%AD%90%E5%AD%97%E7%AC%A6%E4%B8%B2/</id>
    <published>2022-07-09T01:40:12.086Z</published>
    <updated>2022-07-09T01:40:47.066Z</updated>
    
    <content type="html"><![CDATA[<h3 id="题目描述"><a href="#题目描述" class="headerlink" title="题目描述"></a>题目描述</h3><p>请从字符串中找出一个最长的不包含重复字符的子字符串，计算该最长子字符串的长度。</p><p> <strong>示例 1:</strong> </p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">输入: &quot;abcabcbb&quot;</span><br><span class="line">输出: 3 </span><br><span class="line">解释: 因为无重复字符的最长子串是 &quot;abc&quot;，所以其长度为 3。</span><br></pre></td></tr></table></figure><p> <strong>示例 2:</strong> </p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">输入: &quot;bbbbb&quot;</span><br><span class="line">输出: 1</span><br><span class="line">解释: 因为无重复字符的最长子串是 &quot;b&quot;，所以其长度为 1。</span><br></pre></td></tr></table></figure><p> <strong>示例 3:</strong> </p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">输入: &quot;pwwkew&quot;</span><br><span class="line">输出: 3</span><br><span class="line">解释: 因为无重复字符的最长子串是 &quot;wke&quot;，所以其长度为 3。</span><br><span class="line">     请注意，你的答案必须是 子串 的长度，&quot;pwke&quot; 是一个子序列，不是子串。</span><br></pre></td></tr></table></figure><p>提示：</p><ul><li>$s.length &lt;&#x3D; 40000$</li></ul><p>注意：本题与主站 3 题相同：<a href="https://leetcode-cn.com/problems/longest-substring-without-repeating-characters/">https://leetcode-cn.com/problems/longest-substring-without-repeating-characters/</a></p><hr><h3 id="算法"><a href="#算法" class="headerlink" title="算法"></a>算法</h3><h4 id="哈希表，双指针算法-O-n"><a href="#哈希表，双指针算法-O-n" class="headerlink" title="(哈希表，双指针算法)  $O(n)$"></a>(哈希表，双指针算法)  $O(n)$</h4><p>用哈希表存储每个字符出现的次数，且保证区间 $[i, j]$ 内没有重复元素，每个字符只出现一次；$res$ 记录答案。</p><p>双指针扫描字符串</p><ol><li>每次将 $s[i]$ 加入到哈希表中</li><li>如果 $s[i]$ 出现的次数超过 1，说明在 $[j, i - 1]$ 中有重复元素，此时移动 $j$ 指针直到区间 $[j, i]$ 中没有重复元素为止。</li><li>计算区间长度即当前不含重复字符的字符串的长度，更新 res，<code>res = max(res, i - j + 1)</code>。</li></ol><h4 id="时间复杂度"><a href="#时间复杂度" class="headerlink" title="时间复杂度"></a>时间复杂度</h4><p>$i, j$ 最多扫描一遍字符串，所以时间复杂度为 $O(n)$</p><h4 id="空间复杂度"><a href="#空间复杂度" class="headerlink" title="空间复杂度"></a>空间复杂度</h4><p>$O(n)$</p><h4 id="C-代码"><a href="#C-代码" class="headerlink" title="C++ 代码"></a>C++ 代码</h4><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span> &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="type">int</span> <span class="title">lengthOfLongestSubstring</span><span class="params">(string s)</span> </span>&#123;</span><br><span class="line">        unordered_map&lt;<span class="type">int</span>, <span class="type">int</span>&gt; cnt;</span><br><span class="line">        <span class="type">int</span> res = <span class="number">0</span>;</span><br><span class="line">        <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>, j = <span class="number">0</span>; i &lt; s.<span class="built_in">size</span>(); i ++ ) &#123;</span><br><span class="line">            cnt[s[i]] ++ ;</span><br><span class="line">            <span class="keyword">while</span> (cnt[s[i]] &gt; <span class="number">1</span>) cnt[s[j ++ ]] -- ;</span><br><span class="line">            res = <span class="built_in">max</span>(res, i - j + <span class="number">1</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> res;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;题目描述&quot;&gt;&lt;a href=&quot;#题目描述&quot; class=&quot;headerlink&quot; title=&quot;题目描述&quot;&gt;&lt;/a&gt;题目描述&lt;/h3&gt;&lt;p&gt;请从字符串中找出一个最长的不包含重复字符的子字符串，计算该最长子字符串的长度。&lt;/p&gt;
&lt;p&gt; &lt;strong&gt;示例 1:&lt;</summary>
      
    
    
    
    <category term="算法" scheme="https://tonngw.com/categories/%E7%AE%97%E6%B3%95/"/>
    
    <category term="剑指 Offer" scheme="https://tonngw.com/categories/%E7%AE%97%E6%B3%95/%E5%89%91%E6%8C%87-Offer/"/>
    
    
    <category term="双指针" scheme="https://tonngw.com/tags/%E5%8F%8C%E6%8C%87%E9%92%88/"/>
    
    <category term="哈希表" scheme="https://tonngw.com/tags/%E5%93%88%E5%B8%8C%E8%A1%A8/"/>
    
  </entry>
  
  <entry>
    <title>剑指 Offer 21. 调整数组顺序使奇数位于偶数前面</title>
    <link href="https://tonngw.com/2022/07/09/%E5%89%91%E6%8C%87%20Offer/%E5%89%91%E6%8C%87%20Offer%2021.%20%E8%B0%83%E6%95%B4%E6%95%B0%E7%BB%84%E9%A1%BA%E5%BA%8F%E4%BD%BF%E5%A5%87%E6%95%B0%E4%BD%8D%E4%BA%8E%E5%81%B6%E6%95%B0%E5%89%8D%E9%9D%A2/"/>
    <id>https://tonngw.com/2022/07/09/%E5%89%91%E6%8C%87%20Offer/%E5%89%91%E6%8C%87%20Offer%2021.%20%E8%B0%83%E6%95%B4%E6%95%B0%E7%BB%84%E9%A1%BA%E5%BA%8F%E4%BD%BF%E5%A5%87%E6%95%B0%E4%BD%8D%E4%BA%8E%E5%81%B6%E6%95%B0%E5%89%8D%E9%9D%A2/</id>
    <published>2022-07-09T01:33:00.162Z</published>
    <updated>2022-07-09T01:39:57.452Z</updated>
    
    <content type="html"><![CDATA[<h3 id="题目描述"><a href="#题目描述" class="headerlink" title="题目描述"></a>题目描述</h3><p>输入一个整数数组，实现一个函数来调整该数组中数字的顺序，使得所有奇数在数组的前半部分，所有偶数在数组的后半部分。</p><p> <strong>示例：</strong> </p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">输入：nums = [1,2,3,4]</span><br><span class="line">输出：[1,3,2,4] </span><br><span class="line">注：[3,1,2,4] 也是正确的答案之一。</span><br></pre></td></tr></table></figure><p> <strong>提示：</strong> </p><ol><li>$0 &lt;&#x3D; nums.length &lt;&#x3D; 50000$</li><li>$0 &lt;&#x3D; nums[i] &lt;&#x3D; 10000$</li></ol><hr><h3 id="算法"><a href="#算法" class="headerlink" title="算法"></a>算法</h3><h4 id="双指针-位运算-O-n"><a href="#双指针-位运算-O-n" class="headerlink" title="(双指针,位运算))  $O(n)$"></a>(双指针,位运算))  $O(n)$</h4><p>使用两个指针 $l、r$，$l$ 从前往后扫描找到偶数时停止，$r$ 从后往前扫描找到奇数时停止，此时如果 $l &lt; r$ 则交换两个数，循环以上过程直到 $l &gt;&#x3D; r$ 为止。</p><p>小技巧：使用位运算和 $1$ 取 <code>&amp;</code> 的结果判断是奇数还是偶数，在计算机中 $%$ 运算是非常慢的。</p><h4 id="时间复杂度"><a href="#时间复杂度" class="headerlink" title="时间复杂度"></a>时间复杂度</h4><p>$O(n)$</p><h4 id="空间复杂度"><a href="#空间复杂度" class="headerlink" title="空间复杂度"></a>空间复杂度</h4><p>$O(1)$</p><h4 id="C-代码"><a href="#C-代码" class="headerlink" title="C++ 代码"></a>C++ 代码</h4><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span> &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function">vector&lt;<span class="type">int</span>&gt; <span class="title">exchange</span><span class="params">(vector&lt;<span class="type">int</span>&gt;&amp; nums)</span> </span>&#123;</span><br><span class="line">        <span class="type">int</span> l = <span class="number">0</span>, r = nums.<span class="built_in">size</span>() - <span class="number">1</span>;</span><br><span class="line">        <span class="keyword">while</span> (l &lt; r) &#123;</span><br><span class="line">            <span class="keyword">while</span> (l &lt; r &amp;&amp; (nums[l] &amp; <span class="number">1</span>) == <span class="number">1</span>) l ++ ;</span><br><span class="line">            <span class="keyword">while</span> (l &lt; r &amp;&amp; (nums[r] &amp; <span class="number">1</span>) == <span class="number">0</span>) r -- ;</span><br><span class="line">            <span class="keyword">if</span> (l &lt; r) <span class="built_in">swap</span>(nums[l], nums[r]);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> nums;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;题目描述&quot;&gt;&lt;a href=&quot;#题目描述&quot; class=&quot;headerlink&quot; title=&quot;题目描述&quot;&gt;&lt;/a&gt;题目描述&lt;/h3&gt;&lt;p&gt;输入一个整数数组，实现一个函数来调整该数组中数字的顺序，使得所有奇数在数组的前半部分，所有偶数在数组的后半部分。&lt;/p&gt;
&lt;</summary>
      
    
    
    
    <category term="算法" scheme="https://tonngw.com/categories/%E7%AE%97%E6%B3%95/"/>
    
    <category term="剑指 Offer" scheme="https://tonngw.com/categories/%E7%AE%97%E6%B3%95/%E5%89%91%E6%8C%87-Offer/"/>
    
    
    <category term="双指针" scheme="https://tonngw.com/tags/%E5%8F%8C%E6%8C%87%E9%92%88/"/>
    
    <category term="位运算" scheme="https://tonngw.com/tags/%E4%BD%8D%E8%BF%90%E7%AE%97/"/>
    
  </entry>
  
  <entry>
    <title>剑指 Offer 16. 数值的整数次方</title>
    <link href="https://tonngw.com/2022/07/09/%E5%89%91%E6%8C%87%20Offer/%E5%89%91%E6%8C%87%20Offer%2016.%20%E6%95%B0%E5%80%BC%E7%9A%84%E6%95%B4%E6%95%B0%E6%AC%A1%E6%96%B9/"/>
    <id>https://tonngw.com/2022/07/09/%E5%89%91%E6%8C%87%20Offer/%E5%89%91%E6%8C%87%20Offer%2016.%20%E6%95%B0%E5%80%BC%E7%9A%84%E6%95%B4%E6%95%B0%E6%AC%A1%E6%96%B9/</id>
    <published>2022-07-09T01:32:08.239Z</published>
    <updated>2022-07-09T01:32:49.298Z</updated>
    
    <content type="html"><![CDATA[<h3 id="题目描述"><a href="#题目描述" class="headerlink" title="题目描述"></a>题目描述</h3><p>实现 <a href="https://www.cplusplus.com/reference/valarray/pow/">pow(<em>x</em>, <em>n</em>)</a> ，即计算 x 的 n 次幂函数（即，x^{n}）。不得使用库函数，同时不需要考虑大数问题。</p><p> <strong>示例 1：</strong> </p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">输入：x = 2.00000, n = 10</span><br><span class="line">输出：1024.00000</span><br></pre></td></tr></table></figure><p> <strong>示例 2：</strong> </p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">输入：x = 2.10000, n = 3</span><br><span class="line">输出：9.26100</span><br></pre></td></tr></table></figure><p> <strong>示例 3：</strong> </p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">输入：x = 2.00000, n = -2</span><br><span class="line">输出：0.25000</span><br><span class="line">解释：2-2 = 1/22 = 1/4 = 0.25</span><br></pre></td></tr></table></figure><p> <strong>提示：</strong> </p><ul><li>$-100.0 &lt; x &lt; 100.0$</li><li>$-2^{31} &lt;&#x3D; n &lt;&#x3D; 2^{31}-1$</li><li>$-10^{4} &lt;&#x3D; x^{n} &lt;&#x3D; 10^{4}$</li></ul><p>注意：本题与主站 50 题相同：<a href="https://leetcode-cn.com/problems/powx-n/">https://leetcode-cn.com/problems/powx-n/</a></p><hr><h3 id="算法"><a href="#算法" class="headerlink" title="算法"></a>算法</h3><h4 id="快速幂-O-logn"><a href="#快速幂-O-logn" class="headerlink" title="(快速幂)  $O(logn))$"></a>(快速幂)  $O(logn))$</h4><p>思路还是比较直接的，如果指数是负数，先不管负号，按正数来计算乘法的结果，最后再判断如果指数是负数的话，返回用 $1$ 除以答案的结果，否则直接返回即可。</p><p>注意：直接计算乘法会超时，需要用快速幂。</p><h4 id="时间复杂度"><a href="#时间复杂度" class="headerlink" title="时间复杂度"></a>时间复杂度</h4><p>$O(logn))$</p><h4 id="空间复杂度"><a href="#空间复杂度" class="headerlink" title="空间复杂度"></a>空间复杂度</h4><p>$O(1)$</p><h4 id="C-代码"><a href="#C-代码" class="headerlink" title="C++ 代码"></a>C++ 代码</h4><p>写法 1</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span> &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="type">double</span> <span class="title">myPow</span><span class="params">(<span class="type">double</span> x, <span class="type">int</span> _n)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (!x || x == <span class="number">1</span>) <span class="keyword">return</span> x;</span><br><span class="line">        <span class="type">long</span> <span class="type">long</span> n = _n;</span><br><span class="line">        <span class="type">bool</span> is_minus = _n &lt; <span class="number">0</span>;</span><br><span class="line">        n = is_minus ? -n : n;</span><br><span class="line">        </span><br><span class="line">        <span class="comment">// 快速幂</span></span><br><span class="line">        <span class="type">double</span> res = <span class="number">1</span>;</span><br><span class="line">        <span class="keyword">while</span> (n) &#123;</span><br><span class="line">            <span class="keyword">if</span> (n &amp; <span class="number">1</span>) res = res * x;</span><br><span class="line">            x *= x;</span><br><span class="line">            n &gt;&gt;= <span class="number">1</span>; </span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> is_minus ? <span class="number">1</span> / res : res;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>写法 2</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span> &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="type">double</span> <span class="title">myPow</span><span class="params">(<span class="type">double</span> x, <span class="type">int</span> n)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">typedef</span> <span class="type">long</span> <span class="type">long</span> LL;</span><br><span class="line">        <span class="type">double</span> res = <span class="number">1</span>;</span><br><span class="line">        <span class="type">bool</span> is_minus = n &lt; <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">for</span> (LL k = <span class="built_in">abs</span>(<span class="built_in">LL</span>(n)); k; k &gt;&gt;= <span class="number">1</span>) &#123;</span><br><span class="line">            <span class="keyword">if</span> (k &amp; <span class="number">1</span>) res *= x;</span><br><span class="line">            x *= x;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (is_minus) res = <span class="number">1</span> / res;</span><br><span class="line">        <span class="keyword">return</span> res;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;题目描述&quot;&gt;&lt;a href=&quot;#题目描述&quot; class=&quot;headerlink&quot; title=&quot;题目描述&quot;&gt;&lt;/a&gt;题目描述&lt;/h3&gt;&lt;p&gt;实现 &lt;a href=&quot;https://www.cplusplus.com/reference/valarray/pow/&quot;</summary>
      
    
    
    
    <category term="算法" scheme="https://tonngw.com/categories/%E7%AE%97%E6%B3%95/"/>
    
    <category term="剑指 Offer" scheme="https://tonngw.com/categories/%E7%AE%97%E6%B3%95/%E5%89%91%E6%8C%87-Offer/"/>
    
    
    <category term="快速幂" scheme="https://tonngw.com/tags/%E5%BF%AB%E9%80%9F%E5%B9%82/"/>
    
  </entry>
  
  <entry>
    <title>剑指 Offer 11. 旋转数组的最小数字</title>
    <link href="https://tonngw.com/2022/07/09/%E5%89%91%E6%8C%87%20Offer/%E5%89%91%E6%8C%87%20Offer%2053%20-%20II.%200%EF%BD%9En-1%E4%B8%AD%E7%BC%BA%E5%A4%B1%E7%9A%84%E6%95%B0%E5%AD%97/"/>
    <id>https://tonngw.com/2022/07/09/%E5%89%91%E6%8C%87%20Offer/%E5%89%91%E6%8C%87%20Offer%2053%20-%20II.%200%EF%BD%9En-1%E4%B8%AD%E7%BC%BA%E5%A4%B1%E7%9A%84%E6%95%B0%E5%AD%97/</id>
    <published>2022-07-09T01:31:24.406Z</published>
    <updated>2022-07-09T01:31:48.013Z</updated>
    
    <content type="html"><![CDATA[<h3 id="题目描述"><a href="#题目描述" class="headerlink" title="题目描述"></a>题目描述</h3><p>一个长度为n-1的递增排序数组中的所有数字都是唯一的，并且每个数字都在范围0～n-1之内。在范围0～n-1内的n个数字中有且只有一个数字不在该数组中，请找出这个数字。</p><p> <strong>示例 1:</strong> </p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">输入: [0,1,3]</span><br><span class="line">输出: 2</span><br></pre></td></tr></table></figure><p> <strong>示例 2:</strong> </p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">输入: [0,1,2,3,4,5,6,7,9]</span><br><span class="line">输出: 8</span><br></pre></td></tr></table></figure><p> <strong>限制：</strong> </p><p>$1 &lt;&#x3D; 数组长度 &lt;&#x3D; 10000$</p><hr><h3 id="算法"><a href="#算法" class="headerlink" title="算法"></a>算法</h3><h4 id="二分-O-logn"><a href="#二分-O-logn" class="headerlink" title="(二分)  $O(logn)$"></a>(二分)  $O(logn)$</h4><p>已知每个数字在 0 ~ n - 1 之间，但里面少一个数，观察数组的特点可以发现少的那个数一定是第一个大于当前下标的数，即 <code>nums[i] &gt; i</code>，因此可以通过二分 $[0, n - 1]$ 区间寻找答案。</p><p>如果二分没有找到答案那么说明缺少的那个数就是 n - 1。</p><p><strong>注意</strong>：分析的时候长度是 n - 1，代码实现 n 代表的就是数组的长度。</p><h4 id="时间复杂度"><a href="#时间复杂度" class="headerlink" title="时间复杂度"></a>时间复杂度</h4><p>$O(logn)$</p><h4 id="空间复杂度"><a href="#空间复杂度" class="headerlink" title="空间复杂度"></a>空间复杂度</h4><p>$O(1)$</p><h3 id="代码"><a href="#代码" class="headerlink" title="代码"></a>代码</h3><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span> &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="type">int</span> <span class="title">missingNumber</span><span class="params">(vector&lt;<span class="type">int</span>&gt;&amp; nums)</span> </span>&#123;</span><br><span class="line">        <span class="type">int</span> n = nums.<span class="built_in">size</span>(); <span class="comment">// n = 5, n - 1= 4;</span></span><br><span class="line">        <span class="type">int</span> l = <span class="number">0</span>, r = n;</span><br><span class="line">        <span class="keyword">while</span> (l &lt; r) &#123;</span><br><span class="line">            <span class="type">int</span> mid = (l + r) &gt;&gt; <span class="number">1</span>;</span><br><span class="line">            <span class="keyword">if</span> (nums[mid] &gt; mid) r = mid;</span><br><span class="line">            <span class="keyword">else</span> l = mid + <span class="number">1</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> (l == n) <span class="keyword">return</span> n;</span><br><span class="line">        <span class="keyword">return</span> l;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;题目描述&quot;&gt;&lt;a href=&quot;#题目描述&quot; class=&quot;headerlink&quot; title=&quot;题目描述&quot;&gt;&lt;/a&gt;题目描述&lt;/h3&gt;&lt;p&gt;一个长度为n-1的递增排序数组中的所有数字都是唯一的，并且每个数字都在范围0～n-1之内。在范围0～n-1内的n个数字中有且</summary>
      
    
    
    
    <category term="算法" scheme="https://tonngw.com/categories/%E7%AE%97%E6%B3%95/"/>
    
    <category term="剑指 Offer" scheme="https://tonngw.com/categories/%E7%AE%97%E6%B3%95/%E5%89%91%E6%8C%87-Offer/"/>
    
    
    <category term="二分" scheme="https://tonngw.com/tags/%E4%BA%8C%E5%88%86/"/>
    
  </entry>
  
  <entry>
    <title>剑指 Offer 53 - I. 在排序数组中查找数字 I</title>
    <link href="https://tonngw.com/2022/07/09/%E5%89%91%E6%8C%87%20Offer/%E5%89%91%E6%8C%87%20Offer%2053%20-%20I.%20%E5%9C%A8%E6%8E%92%E5%BA%8F%E6%95%B0%E7%BB%84%E4%B8%AD%E6%9F%A5%E6%89%BE%E6%95%B0%E5%AD%97%20I/"/>
    <id>https://tonngw.com/2022/07/09/%E5%89%91%E6%8C%87%20Offer/%E5%89%91%E6%8C%87%20Offer%2053%20-%20I.%20%E5%9C%A8%E6%8E%92%E5%BA%8F%E6%95%B0%E7%BB%84%E4%B8%AD%E6%9F%A5%E6%89%BE%E6%95%B0%E5%AD%97%20I/</id>
    <published>2022-07-09T01:30:23.088Z</published>
    <updated>2022-07-09T01:31:04.828Z</updated>
    
    <content type="html"><![CDATA[<h3 id="题目描述"><a href="#题目描述" class="headerlink" title="题目描述"></a>题目描述</h3><p>统计一个数字在排序数组中出现的次数。</p><p> <strong>示例 1:</strong> </p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">输入: nums = [5,7,7,8,8,10], target = 8</span><br><span class="line">输出: 2</span><br></pre></td></tr></table></figure><p> <strong>示例 2:</strong> </p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">输入: nums = [5,7,7,8,8,10], target = 6</span><br><span class="line">输出: 0</span><br></pre></td></tr></table></figure><p> <strong>提示：</strong> </p><ul><li>$0 &lt;&#x3D; nums.length &lt;&#x3D; 10^{5}$</li><li>$-10^{9} &lt;&#x3D; nums[i] &lt;&#x3D; 10^{9}$</li><li>$nums$ 是一个非递减数组</li><li>$-10^{9} &lt;&#x3D; target &lt;&#x3D; 10^{9}$</li></ul><p> <strong>注意：</strong> 本题与主站 34 题相同（仅返回值不同）：<a href="https://leetcode-cn.com/problems/find-first-and-last-position-of-element-in-sorted-array/">https://leetcode-cn.com/problems/find-first-and-last-position-of-element-in-sorted-array/</a></p><hr><h3 id="算法"><a href="#算法" class="headerlink" title="算法"></a>算法</h3><h4 id="二分-O-logn"><a href="#二分-O-logn" class="headerlink" title="(二分)  $O(logn)$"></a>(二分)  $O(logn)$</h4><p>在排序数组中快速找一个数可以用二分，题目要求找出连续的一段数 $target$ 的个数，可以做两次二分，二分左端点和二分右端点。</p><p>算法步骤：</p><ol><li>二分左端点的条件：找到第一个大于等于 $target$ 的数的位置 $left$</li><li>二分结束，如果左端点对应的值不是 $target$，说明 $target$ 不存在，直接返回 $0$，否则继续二分右端点</li><li>二分右端点的条件：找到最后一个个小于等于 $target$ 的数的位置 $right$</li></ol><p>最后返回出现的次数 $right - left + 1$。</p><h4 id="时间复杂度"><a href="#时间复杂度" class="headerlink" title="时间复杂度"></a>时间复杂度</h4><p>二分的时间复杂度为 $O(logn)$</p><h4 id="空间复杂度"><a href="#空间复杂度" class="headerlink" title="空间复杂度"></a>空间复杂度</h4><p>$O(1)$</p><h4 id="C-代码"><a href="#C-代码" class="headerlink" title="C++ 代码"></a>C++ 代码</h4><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span> &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="type">int</span> <span class="title">search</span><span class="params">(vector&lt;<span class="type">int</span>&gt;&amp; nums, <span class="type">int</span> target)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (nums.<span class="built_in">empty</span>()) <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">        <span class="type">int</span> l = <span class="number">0</span>, r = nums.<span class="built_in">size</span>() - <span class="number">1</span>;</span><br><span class="line">        <span class="keyword">while</span> (l &lt; r) &#123;</span><br><span class="line">            <span class="type">int</span> mid = l + r &gt;&gt; <span class="number">1</span>;</span><br><span class="line">            <span class="keyword">if</span> (nums[mid] &gt;= target) r = mid;</span><br><span class="line">            <span class="keyword">else</span> l = mid + <span class="number">1</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (nums[l] != target) <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">        <span class="type">int</span> left = l;</span><br><span class="line">        l = <span class="number">0</span>, r = nums.<span class="built_in">size</span>() - <span class="number">1</span>;</span><br><span class="line">        <span class="keyword">while</span> (l &lt; r) &#123;</span><br><span class="line">            <span class="type">int</span> mid = l + r + <span class="number">1ll</span> &gt;&gt; <span class="number">1</span>;</span><br><span class="line">            <span class="keyword">if</span> (nums[mid] &lt;= target) l = mid;</span><br><span class="line">            <span class="keyword">else</span> r = mid - <span class="number">1</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> r - left + <span class="number">1</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;题目描述&quot;&gt;&lt;a href=&quot;#题目描述&quot; class=&quot;headerlink&quot; title=&quot;题目描述&quot;&gt;&lt;/a&gt;题目描述&lt;/h3&gt;&lt;p&gt;统计一个数字在排序数组中出现的次数。&lt;/p&gt;
&lt;p&gt; &lt;strong&gt;示例 1:&lt;/strong&gt; &lt;/p&gt;
&lt;figure</summary>
      
    
    
    
    <category term="算法" scheme="https://tonngw.com/categories/%E7%AE%97%E6%B3%95/"/>
    
    <category term="剑指 Offer" scheme="https://tonngw.com/categories/%E7%AE%97%E6%B3%95/%E5%89%91%E6%8C%87-Offer/"/>
    
    
    <category term="二分" scheme="https://tonngw.com/tags/%E4%BA%8C%E5%88%86/"/>
    
  </entry>
  
  <entry>
    <title>剑指 Offer 64. 求1+2+…+n</title>
    <link href="https://tonngw.com/2022/07/09/%E5%89%91%E6%8C%87%20Offer/%E5%89%91%E6%8C%87%20Offer%2064.%20%E6%B1%821+2+%E2%80%A6+n/"/>
    <id>https://tonngw.com/2022/07/09/%E5%89%91%E6%8C%87%20Offer/%E5%89%91%E6%8C%87%20Offer%2064.%20%E6%B1%821+2+%E2%80%A6+n/</id>
    <published>2022-07-09T01:28:01.288Z</published>
    <updated>2022-07-09T01:29:50.751Z</updated>
    
    <content type="html"><![CDATA[<h3 id="题目描述"><a href="#题目描述" class="headerlink" title="题目描述"></a>题目描述</h3><p>求 $1+2+…+n$ ，要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句（A?B:C）。</p><p> <strong>示例 1：</strong> </p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">输入: n = 3</span><br><span class="line">输出: 6</span><br></pre></td></tr></table></figure><p> <strong>示例 2：</strong> </p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">输入: n = 9</span><br><span class="line">输出: 45</span><br></pre></td></tr></table></figure><p> <strong>限制：</strong> </p><ul><li>$1 &lt;&#x3D; n &lt;&#x3D; 10000$</li></ul><hr><h3 id="算法"><a href="#算法" class="headerlink" title="算法"></a>算法</h3><h4 id="递归-O-n"><a href="#递归-O-n" class="headerlink" title="(递归)  $O(n)$"></a>(递归)  $O(n)$</h4><p>递归求解替换 $for$ 循环 $1 + 2 + … + n$<br>只不过需要将 $if$ 替换掉，依据 <code>A &amp;&amp; B</code> 的性质，如果 A 为 false，B 就不执行，如果 A 是 true，B 还要进行判断。同样的对于 <code>A || B</code> 依然有类似的性质，如果 A 是 true，B 就不执行，如果 A 是 false，B 还要进行判断。</p><p>因此我们可以用逻辑与 <code>&amp;&amp;​</code> 运算符将 if 完美替换<br><code>if (n &gt; 0) res += getSum(n - 1)</code> -&gt; <code>n &gt; 0 &amp;&amp; (res += getSum(n - 1))</code></p><h4 id="时间复杂度"><a href="#时间复杂度" class="headerlink" title="时间复杂度"></a>时间复杂度</h4><p>递归 $n$ 次，时间复杂度为 $O(n)$</p><h4 id="时间复杂度-1"><a href="#时间复杂度-1" class="headerlink" title="时间复杂度"></a>时间复杂度</h4><p>递归系统调用栈的空间为 $O(n)$</p><h4 id="C-代码"><a href="#C-代码" class="headerlink" title="C++ 代码"></a>C++ 代码</h4><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span> &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="type">int</span> <span class="title">sumNums</span><span class="params">(<span class="type">int</span> n)</span> </span>&#123;</span><br><span class="line">        <span class="type">int</span> res = n;</span><br><span class="line">        n &gt; <span class="number">0</span> &amp;&amp; (res += <span class="built_in">sumNums</span>(n - <span class="number">1</span>));</span><br><span class="line">        <span class="keyword">return</span> res;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;题目描述&quot;&gt;&lt;a href=&quot;#题目描述&quot; class=&quot;headerlink&quot; title=&quot;题目描述&quot;&gt;&lt;/a&gt;题目描述&lt;/h3&gt;&lt;p&gt;求 $1+2+…+n$ ，要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语</summary>
      
    
    
    
    <category term="算法" scheme="https://tonngw.com/categories/%E7%AE%97%E6%B3%95/"/>
    
    <category term="剑指 Offer" scheme="https://tonngw.com/categories/%E7%AE%97%E6%B3%95/%E5%89%91%E6%8C%87-Offer/"/>
    
    
    <category term="递归" scheme="https://tonngw.com/tags/%E9%80%92%E5%BD%92/"/>
    
    <category term="位运算" scheme="https://tonngw.com/tags/%E4%BD%8D%E8%BF%90%E7%AE%97/"/>
    
    <category term="逻辑运算符" scheme="https://tonngw.com/tags/%E9%80%BB%E8%BE%91%E8%BF%90%E7%AE%97%E7%AC%A6/"/>
    
  </entry>
  
  <entry>
    <title>剑指 Offer 65. 不用加减乘除做加法</title>
    <link href="https://tonngw.com/2022/07/09/%E5%89%91%E6%8C%87%20Offer/%E5%89%91%E6%8C%87%20Offer%2065.%20%E4%B8%8D%E7%94%A8%E5%8A%A0%E5%87%8F%E4%B9%98%E9%99%A4%E5%81%9A%E5%8A%A0%E6%B3%95/"/>
    <id>https://tonngw.com/2022/07/09/%E5%89%91%E6%8C%87%20Offer/%E5%89%91%E6%8C%87%20Offer%2065.%20%E4%B8%8D%E7%94%A8%E5%8A%A0%E5%87%8F%E4%B9%98%E9%99%A4%E5%81%9A%E5%8A%A0%E6%B3%95/</id>
    <published>2022-07-09T01:23:54.501Z</published>
    <updated>2022-07-09T01:27:56.193Z</updated>
    
    <content type="html"><![CDATA[<h3 id="题目描述"><a href="#题目描述" class="headerlink" title="题目描述"></a>题目描述</h3><p>写一个函数，求两个整数之和，要求在函数体内不得使用 “+”、“-”、“*”、“&#x2F;” 四则运算符号。</p><p> <strong>示例:</strong> </p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">输入: a = 1, b = 1</span><br><span class="line">输出: 2</span><br></pre></td></tr></table></figure><p> <strong>提示：</strong> </p><ul><li>$a$, $b$ 均可能是负数或 0</li><li>结果不会溢出 32 位整数</li></ul><hr><h3 id="算法"><a href="#算法" class="headerlink" title="算法"></a>算法</h3><h4 id="位运算-O-logn"><a href="#位运算-O-logn" class="headerlink" title="(位运算)  $O(logn)$"></a>(位运算)  $O(logn)$</h4><ol><li>首先我们可以将 $num1 + num2 &#x3D; A + B$，A 是 $num1 + num2$ 做不进位加法的结果，B 是 $num1 + num2$ 产生的进位结果，两部分加起来就是 $num1 + num2$</li><li>不进位加法可以用异或 <code>^</code>，计算进位可以用与 <code>&amp;</code>，对每一位进行这两种操作</li><li>因为不能用加法，所以 $A + B$ 可以用 whlie 循环代替<br>循环终止条件：由于每次计算进位的结果 $carry$ 会左移 1 位，后面补 0，再计算新的进位做 <code>&amp;</code> 运算时后面的 0 还是 0 不会出现 1，所以在不断的移位后 $carry$ 必然会变成 0，循环可以结束<br>循环内部：每次 $num1$ 和 $num2 &#x2F; carry$ 做不进位加法，计算新产生的进位（为什么会有新的进位，因为 $sum$ 的结果和进位结果做不进位加法后可能还会出现新的进位），直到没有进位为止计算结束，$num1$ 中存的就是 <code>num1 + num2</code> 的结果</li><li>!注意：此做法只能做正数加法</li></ol><h4 id="时间复杂度"><a href="#时间复杂度" class="headerlink" title="时间复杂度"></a>时间复杂度</h4><p>进位 $carry$ 每次左移 $1$ 位相当于除以 $2$，$logn$ 次 $carry$ 为 $0$，所以时间复杂度为 $O(logn)$</p><h4 id="空间复杂度"><a href="#空间复杂度" class="headerlink" title="空间复杂度"></a>空间复杂度</h4><p>$O(1)$</p><h3 id="代码"><a href="#代码" class="headerlink" title="代码"></a>代码</h3><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span> &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="type">int</span> <span class="title">add</span><span class="params">(<span class="type">int</span> a, <span class="type">int</span> b)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">while</span> (b) &#123;</span><br><span class="line">            <span class="type">int</span> sum = a ^ b;</span><br><span class="line">            <span class="type">int</span> carry = (<span class="type">unsigned</span> <span class="type">int</span>) (a &amp; b) &lt;&lt; <span class="number">1</span>;</span><br><span class="line">            a = sum;</span><br><span class="line">            b = carry;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> a;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;题目描述&quot;&gt;&lt;a href=&quot;#题目描述&quot; class=&quot;headerlink&quot; title=&quot;题目描述&quot;&gt;&lt;/a&gt;题目描述&lt;/h3&gt;&lt;p&gt;写一个函数，求两个整数之和，要求在函数体内不得使用 “+”、“-”、“*”、“&amp;#x2F;” 四则运算符号。&lt;/p&gt;
&lt;p&gt;</summary>
      
    
    
    
    <category term="算法" scheme="https://tonngw.com/categories/%E7%AE%97%E6%B3%95/"/>
    
    <category term="剑指 Offer" scheme="https://tonngw.com/categories/%E7%AE%97%E6%B3%95/%E5%89%91%E6%8C%87-Offer/"/>
    
    
    <category term="位运算" scheme="https://tonngw.com/tags/%E4%BD%8D%E8%BF%90%E7%AE%97/"/>
    
  </entry>
  
  <entry>
    <title>剑指 Offer 56 - II. 数组中数字出现的次数 II</title>
    <link href="https://tonngw.com/2022/07/09/%E5%89%91%E6%8C%87%20Offer/%E5%89%91%E6%8C%87%20Offer%2056%20-%20II.%20%E6%95%B0%E7%BB%84%E4%B8%AD%E6%95%B0%E5%AD%97%E5%87%BA%E7%8E%B0%E7%9A%84%E6%AC%A1%E6%95%B0%20II/"/>
    <id>https://tonngw.com/2022/07/09/%E5%89%91%E6%8C%87%20Offer/%E5%89%91%E6%8C%87%20Offer%2056%20-%20II.%20%E6%95%B0%E7%BB%84%E4%B8%AD%E6%95%B0%E5%AD%97%E5%87%BA%E7%8E%B0%E7%9A%84%E6%AC%A1%E6%95%B0%20II/</id>
    <published>2022-07-09T01:22:37.587Z</published>
    <updated>2022-07-09T01:23:15.160Z</updated>
    
    <content type="html"><![CDATA[<h3 id="题目描述"><a href="#题目描述" class="headerlink" title="题目描述"></a>题目描述</h3><p>在一个数组 $nums$ 中除一个数字只出现一次之外，其他数字都出现了三次。请找出那个只出现一次的数字。</p><p> <strong>示例 1：</strong> </p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">输入：nums = [3,4,3,3]</span><br><span class="line">输出：4</span><br></pre></td></tr></table></figure><p> <strong>示例 2：</strong> </p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">输入：nums = [9,1,7,9,7,9,7]</span><br><span class="line">输出：1</span><br></pre></td></tr></table></figure><p> <strong>限制：</strong> </p><ul><li>$1 &lt;&#x3D; nums.length &lt;&#x3D; 10000$</li><li>$1 &lt;&#x3D; nums[i] &lt; 2^31$</li></ul><hr><h3 id="算法"><a href="#算法" class="headerlink" title="算法"></a>算法</h3><h4 id="位运算-O-32n"><a href="#位运算-O-32n" class="headerlink" title="(位运算)  $O(32n)$"></a>(位运算)  $O(32n)$</h4><p>枚举每个数的每一位，用 $one$ 记录每一位 $1$ 出现的个数，如果 <code>one % 3 == 1</code> 说明答案中的当前位是 $1$，否则 <code>one % 3 == 0</code> 说明答案中的当前位不是 $1$，只有这两种情况，因为剩下的数都出现了三次，只有答案是出现一次的数字，所以处理完每一位之后就可以得到答案，这个方法还是比较好理解的。</p><h4 id="时间复杂度"><a href="#时间复杂度" class="headerlink" title="时间复杂度"></a>时间复杂度</h4><p>枚举数字的每一位，每个数字 $32$ 位，总共 $n$ 个数，所以时间复杂度为 $O(32n)$，但这个算法其实不是 $O(n)$ 的，假设 n 的范围是 $10^6$，则 $ logn &lt; 32 $，所以此算法时间复杂度是大于 $O(nlogn)$ 的。</p><h4 id="空间复杂度"><a href="#空间复杂度" class="headerlink" title="空间复杂度"></a>空间复杂度</h4><p>$O(1)$</p><h4 id="C-代码"><a href="#C-代码" class="headerlink" title="C++ 代码"></a>C++ 代码</h4><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span> &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="type">int</span> <span class="title">singleNumber</span><span class="params">(vector&lt;<span class="type">int</span>&gt;&amp; nums)</span> </span>&#123;</span><br><span class="line">        <span class="type">int</span> res = <span class="number">0</span>;</span><br><span class="line">        <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i &lt; <span class="number">32</span>; i ++ ) &#123;</span><br><span class="line">            <span class="type">int</span> one = <span class="number">0</span>;</span><br><span class="line">            <span class="keyword">for</span> (<span class="keyword">auto</span> x : nums)</span><br><span class="line">                <span class="keyword">if</span> (x &gt;&gt; i &amp; <span class="number">1</span>)</span><br><span class="line">                    one ++ ;</span><br><span class="line">            <span class="keyword">if</span> (one % <span class="number">3</span> == <span class="number">1</span>) res += (<span class="number">1</span> &lt;&lt; i);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> res;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;题目描述&quot;&gt;&lt;a href=&quot;#题目描述&quot; class=&quot;headerlink&quot; title=&quot;题目描述&quot;&gt;&lt;/a&gt;题目描述&lt;/h3&gt;&lt;p&gt;在一个数组 $nums$ 中除一个数字只出现一次之外，其他数字都出现了三次。请找出那个只出现一次的数字。&lt;/p&gt;
&lt;p&gt; &lt;</summary>
      
    
    
    
    <category term="算法" scheme="https://tonngw.com/categories/%E7%AE%97%E6%B3%95/"/>
    
    <category term="剑指 Offer" scheme="https://tonngw.com/categories/%E7%AE%97%E6%B3%95/%E5%89%91%E6%8C%87-Offer/"/>
    
    
    <category term="位运算" scheme="https://tonngw.com/tags/%E4%BD%8D%E8%BF%90%E7%AE%97/"/>
    
  </entry>
  
</feed>
