<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Klavor&#39;s Blog</title>
  
  <subtitle>Just do IT!</subtitle>
  <link href="https://www.klavor.com/atom.xml" rel="self"/>
  
  <link href="https://www.klavor.com/"/>
  <updated>2025-11-01T00:45:46.344Z</updated>
  <id>https://www.klavor.com/</id>
  
  <author>
    <name>klavor.com</name>
    
  </author>
  
  <generator uri="https://hexo.io/">Hexo</generator>
  
  <entry>
    <title>「解决方案」Android Vector动画实现三个小球循环转动的加载动画</title>
    <link href="https://www.klavor.com/dev/20240330-1005.html"/>
    <id>https://www.klavor.com/dev/20240330-1005.html</id>
    <published>2024-03-29T16:00:00.000Z</published>
    <updated>2025-11-01T00:45:46.344Z</updated>
    
    <content type="html"><![CDATA[<p>公司项目中需要使用到一个三个小球循环转动的加载动画，最初给的是一帧帧的切图做帧动画，后来在android sdk25上面发生了内存泄漏Out Of Memory(OOM)，于是就考虑着更换一下实现方式，于是就开始尝试使用Vector矢量动画来实现了。</p><h3 id="效果预览"><a href="#效果预览" class="headerlink" title="效果预览"></a>效果预览</h3><p><img src="https://img.klavor.com/2024/03/android_vector_animation_loading.gif" alt="Vector矢量加载动画"></p><h3 id="原始Vector"><a href="#原始Vector" class="headerlink" title="原始Vector"></a>原始Vector</h3><p>在drawable目录下创建一个名为icon_pull_refresh的xml文件。代码如下：</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><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></pre></td><td class="code"><pre><span class="line">&lt;vector xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;</span><br><span class="line">    android:width=&quot;600dp&quot;</span><br><span class="line">    android:height=&quot;200dp&quot;</span><br><span class="line">    android:viewportWidth=&quot;600&quot;</span><br><span class="line">    android:viewportHeight=&quot;200&quot;&gt;</span><br><span class="line"></span><br><span class="line">    &lt;group android:name=&quot;left&quot;&gt;</span><br><span class="line">        &lt;path</span><br><span class="line">            android:fillColor=&quot;#FF00FF&quot;</span><br><span class="line">            android:pathData=&quot;M75 148 a 48 48 0 1 0 -1 0z&quot; /&gt;</span><br><span class="line">    &lt;/group&gt;</span><br><span class="line"></span><br><span class="line">    &lt;group android:name=&quot;middle&quot;&gt;</span><br><span class="line">        &lt;path</span><br><span class="line">            android:fillColor=&quot;#FF00FF&quot;</span><br><span class="line">            android:pathData=&quot;M300 175 a 75 75 0 1 0 -1 0z&quot; /&gt;</span><br><span class="line">    &lt;/group&gt;</span><br><span class="line"></span><br><span class="line">    &lt;group android:name=&quot;right&quot;&gt;</span><br><span class="line">        &lt;path</span><br><span class="line">            android:fillColor=&quot;#FF00FF&quot;</span><br><span class="line">            android:pathData=&quot;M525 148 a 48 48 0 1 0 -1 0z&quot; /&gt;</span><br><span class="line">    &lt;/group&gt;</span><br><span class="line">    </span><br><span class="line">&lt;/vector&gt;</span><br></pre></td></tr></table></figure><h3 id="属性动画"><a href="#属性动画" class="headerlink" title="属性动画"></a>属性动画</h3><h4 id="左侧小球转动到中间"><a href="#左侧小球转动到中间" class="headerlink" title="左侧小球转动到中间"></a>左侧小球转动到中间</h4><p>在animator目录下创建名为animator_pull_refresh_left2middle的xml文件。代码如下：</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><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></pre></td><td class="code"><pre><span class="line">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;</span><br><span class="line">&lt;set xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;&gt;</span><br><span class="line"></span><br><span class="line">    &lt;objectAnimator</span><br><span class="line">        android:duration=&quot;1000&quot;</span><br><span class="line">        android:propertyName=&quot;translateX&quot;</span><br><span class="line">        android:repeatCount=&quot;infinite&quot;</span><br><span class="line">        android:repeatMode=&quot;restart&quot;</span><br><span class="line">        android:valueFrom=&quot;0&quot;</span><br><span class="line">        android:valueTo=&quot;182.8125&quot;</span><br><span class="line">        android:valueType=&quot;floatType&quot;/&gt;</span><br><span class="line"></span><br><span class="line">    &lt;objectAnimator</span><br><span class="line">        android:duration=&quot;1000&quot;</span><br><span class="line">        android:propertyName=&quot;translateY&quot;</span><br><span class="line">        android:repeatCount=&quot;infinite&quot;</span><br><span class="line">        android:repeatMode=&quot;restart&quot;</span><br><span class="line">        android:valueFrom=&quot;0&quot;</span><br><span class="line">        android:valueTo=&quot;-56.25&quot;</span><br><span class="line">        android:valueType=&quot;floatType&quot;/&gt;</span><br><span class="line"></span><br><span class="line">    &lt;objectAnimator</span><br><span class="line">        android:duration=&quot;1000&quot;</span><br><span class="line">        android:propertyName=&quot;scaleX&quot;</span><br><span class="line">        android:repeatCount=&quot;infinite&quot;</span><br><span class="line">        android:repeatMode=&quot;restart&quot;</span><br><span class="line">        android:valueFrom=&quot;1&quot;</span><br><span class="line">        android:valueTo=&quot;1.5625&quot;</span><br><span class="line">        android:valueType=&quot;floatType&quot;/&gt;</span><br><span class="line"></span><br><span class="line">    &lt;objectAnimator</span><br><span class="line">        android:duration=&quot;1000&quot;</span><br><span class="line">        android:propertyName=&quot;scaleY&quot;</span><br><span class="line">        android:repeatCount=&quot;infinite&quot;</span><br><span class="line">        android:repeatMode=&quot;restart&quot;</span><br><span class="line">        android:valueFrom=&quot;1&quot;</span><br><span class="line">        android:valueTo=&quot;1.5625&quot;</span><br><span class="line">        android:valueType=&quot;floatType&quot;/&gt;</span><br><span class="line"></span><br><span class="line">&lt;/set&gt;</span><br></pre></td></tr></table></figure><h4 id="中间小球转动到右边"><a href="#中间小球转动到右边" class="headerlink" title="中间小球转动到右边"></a>中间小球转动到右边</h4><p>在animator目录下创建名为animator_pull_refresh_middle2right的xml文件。代码如下：</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><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">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;</span><br><span class="line">&lt;set xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;&gt;</span><br><span class="line"></span><br><span class="line">    &lt;objectAnimator</span><br><span class="line">        android:duration=&quot;1000&quot;</span><br><span class="line">        android:propertyName=&quot;translateX&quot;</span><br><span class="line">        android:repeatCount=&quot;infinite&quot;</span><br><span class="line">        android:repeatMode=&quot;restart&quot;</span><br><span class="line">        android:valueFrom=&quot;0&quot;</span><br><span class="line">        android:valueTo=&quot;333&quot;</span><br><span class="line">        android:valueType=&quot;floatType&quot;/&gt;</span><br><span class="line"></span><br><span class="line">    &lt;objectAnimator</span><br><span class="line">        android:duration=&quot;1000&quot;</span><br><span class="line">        android:propertyName=&quot;translateY&quot;</span><br><span class="line">        android:repeatCount=&quot;infinite&quot;</span><br><span class="line">        android:repeatMode=&quot;restart&quot;</span><br><span class="line">        android:valueFrom=&quot;0&quot;</span><br><span class="line">        android:valueTo=&quot;36&quot;</span><br><span class="line">        android:valueType=&quot;floatType&quot;/&gt;</span><br><span class="line"></span><br><span class="line">    &lt;objectAnimator</span><br><span class="line">        android:duration=&quot;1000&quot;</span><br><span class="line">        android:propertyName=&quot;scaleX&quot;</span><br><span class="line">        android:repeatCount=&quot;infinite&quot;</span><br><span class="line">        android:repeatMode=&quot;restart&quot;</span><br><span class="line">        android:valueFrom=&quot;1&quot;</span><br><span class="line">        android:valueTo=&quot;0.64&quot;</span><br><span class="line">        android:valueType=&quot;floatType&quot;/&gt;</span><br><span class="line"></span><br><span class="line">    &lt;objectAnimator</span><br><span class="line">        android:duration=&quot;1000&quot;</span><br><span class="line">        android:propertyName=&quot;scaleY&quot;</span><br><span class="line">        android:repeatCount=&quot;infinite&quot;</span><br><span class="line">        android:repeatMode=&quot;restart&quot;</span><br><span class="line">        android:valueFrom=&quot;1&quot;</span><br><span class="line">        android:valueTo=&quot;0.64&quot;</span><br><span class="line">        android:valueType=&quot;floatType&quot;/&gt;</span><br><span class="line">&lt;/set&gt;</span><br></pre></td></tr></table></figure><h4 id="右侧小球转动到左边"><a href="#右侧小球转动到左边" class="headerlink" title="右侧小球转动到左边"></a>右侧小球转动到左边</h4><p>在animator目录下创建名为animator_pull_refresh_right2left的xml文件。代码如下：</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><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">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;</span><br><span class="line">&lt;set&gt;</span><br><span class="line"></span><br><span class="line">    &lt;objectAnimator xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;</span><br><span class="line">        android:duration=&quot;1000&quot;</span><br><span class="line">        android:propertyName=&quot;translateX&quot;</span><br><span class="line">        android:repeatCount=&quot;infinite&quot;</span><br><span class="line">        android:repeatMode=&quot;restart&quot;</span><br><span class="line">        android:valueFrom=&quot;0&quot;</span><br><span class="line">        android:valueTo=&quot;-450&quot;</span><br><span class="line">        android:valueType=&quot;floatType&quot;/&gt;</span><br><span class="line"></span><br><span class="line">&lt;/set&gt;</span><br></pre></td></tr></table></figure><h3 id="Vector矢量动画实现"><a href="#Vector矢量动画实现" class="headerlink" title="Vector矢量动画实现"></a>Vector矢量动画实现</h3><p>在drawble目录下创建名为animation_refresh的xml文件。代码如下：</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><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">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;</span><br><span class="line">&lt;animated-vector</span><br><span class="line">    xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;</span><br><span class="line">    android:drawable=&quot;@drawable/icon_pull_refresh&quot;&gt;</span><br><span class="line">    &lt;target</span><br><span class="line">        android:name=&quot;left&quot;</span><br><span class="line">        android:animation=&quot;@animator/animator_pull_refresh_left2middle&quot; /&gt;</span><br><span class="line">    &lt;target</span><br><span class="line">        android:name=&quot;middle&quot;</span><br><span class="line">        android:animation=&quot;@animator/animator_pull_refresh_middle2right&quot; /&gt;</span><br><span class="line">    &lt;target</span><br><span class="line">        android:name=&quot;right&quot;</span><br><span class="line">        android:animation=&quot;@animator/animator_pull_refresh_right2left&quot; /&gt;</span><br><span class="line">&lt;/animated-vector&gt;</span><br></pre></td></tr></table></figure><h3 id="使用矢量动画"><a href="#使用矢量动画" class="headerlink" title="使用矢量动画"></a>使用矢量动画</h3><p>在布局文件中使用矢量动画</p><figure class="highlight xml"><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="tag">&lt;<span class="name">androidx.appcompat.widget.AppCompatImageView</span></span></span><br><span class="line"><span class="tag">    <span class="attr">app:srcCompat</span>=<span class="string">&quot;@drawable/animation_refresh&quot;</span></span></span><br><span class="line"><span class="tag">    <span class="attr">android:layout_width</span>=<span class="string">&quot;wrap_content&quot;</span></span></span><br><span class="line"><span class="tag">    <span class="attr">android:id</span>=<span class="string">&quot;@+id/aciv_refresh&quot;</span></span></span><br><span class="line"><span class="tag">    <span class="attr">android:layout_height</span>=<span class="string">&quot;wrap_content&quot;</span> /&gt;</span></span><br></pre></td></tr></table></figure><p>在代码中执行矢量动画</p><figure class="highlight kotlin"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">(acivRefresh.drawable <span class="keyword">as</span> AnimatedVectorDrawable).start()</span><br></pre></td></tr></table></figure><h3 id="写在最后"><a href="#写在最后" class="headerlink" title="写在最后"></a>写在最后</h3><p>最终Android Vector矢量动画方案实现了三个小球循环转动的加载动画。但是由于实现方案复杂，改动困难最终方案又被pass了。考虑到现在sdk25存量已经比较小了，因此不考虑使用此替代方案。最终把关注点放到了内存泄漏上。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;公司项目中需要使用到一个三个小球循环转动的加载动画，最初给的是一帧帧的切图做帧动画，后来在android sdk25上面发生了内存泄漏Out Of Memory(OOM)，于是就考虑着更换一下实现方式，于是就开始尝试使用Vector矢量动画来实现了。&lt;/p&gt;
&lt;h3 id=</summary>
      
    
    
    
    <category term="dev" scheme="https://www.klavor.com/categories/dev/"/>
    
    
    <category term="Android" scheme="https://www.klavor.com/tags/Android/"/>
    
    <category term="解决方案" scheme="https://www.klavor.com/tags/%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88/"/>
    
    <category term="Vector" scheme="https://www.klavor.com/tags/Vector/"/>
    
    <category term="加载动画" scheme="https://www.klavor.com/tags/%E5%8A%A0%E8%BD%BD%E5%8A%A8%E7%94%BB/"/>
    
    <category term="矢量动画" scheme="https://www.klavor.com/tags/%E7%9F%A2%E9%87%8F%E5%8A%A8%E7%94%BB/"/>
    
  </entry>
  
  <entry>
    <title>「解决方案」JDK11环境下的Android/Java项目中导入tools.jar包依赖</title>
    <link href="https://www.klavor.com/dev/20210129-1001.html"/>
    <id>https://www.klavor.com/dev/20210129-1001.html</id>
    <published>2021-01-28T16:00:00.000Z</published>
    <updated>2025-11-01T00:45:46.344Z</updated>
    
    <content type="html"><![CDATA[<p>首先，来说一下今天写这篇文章的目的。从JDK9开始，JDK安装包中就不再包含tools.jar包了，那么之前所使用的依赖方式就失效了，那么我们应该如何在新版本中去解决这个以来问题，从而不影响我们的项目正常编译呢？<br>在开发时，我们可能会在编译前或编译后通过一些手段去修改Java生成的字节码。比如使用JavaParser生成或修改源代码，使用Javapoet生成Java类，又或者通过Javassist修改class字节码文件。各种各样的方法层出不穷，我们可以根据自己的场景去选取合适工具。而在一些情况下，我们可能希望在编译前通过修改Java的抽象语法树来改变编译所生成的class字节码文件。这个时候我们就可以考虑使用JDK中的tools.jar来处理这个问题了。<br>那么，在项目中我们要怎么去依赖/引入tools.jar包呢？这里我会分别从JDK8/JDK11和Gradle项目和纯Java项目这几个维度去说明如何引入tools.jar依赖包，并且本文中使用的IDE是Intellij IDEA。毕竟买了正版软件，不用起来就浪费了。</p><h3 id="JDK8-amp-Gradle"><a href="#JDK8-amp-Gradle" class="headerlink" title="JDK8 &amp; Gradle"></a>JDK8 &amp; Gradle</h3><p>在项目的build.gradle中添加如下依赖。</p><figure class="highlight gradle"><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">dependencies</span> &#123;</span><br><span class="line">    implementation files(<span class="string">&#x27;C:\\Program Files\\Java\\jdk1.8.0_251\\lib\\tools.jar&#x27;</span>)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>如果你已经配置了环境变量，则可以使用以下方式进行依赖。</p><figure class="highlight gradle"><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="keyword">dependencies</span> &#123;</span><br><span class="line"><span class="comment">//    implementation files(&#x27;C:\\Program Files\\Java\\jdk1.8.0_251\\lib\\tools.jar&#x27;)</span></span><br><span class="line">    implementation files(System.getenv(<span class="string">&#x27;JAVA_HOME&#x27;</span>) + <span class="string">&#x27;/lib/tools.jar&#x27;</span>)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>JDK8下的配置应该问题不大，身为开发者应该都知道怎么去依赖。</p><h3 id="JDK8-amp-Java"><a href="#JDK8-amp-Java" class="headerlink" title="JDK8 &amp; Java"></a>JDK8 &amp; Java</h3><p>修改项目根目录下的.iml文件，在原有文件的<orderEntry>…</orderEntry>后面加上如下配置：</p><figure class="highlight xml"><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="tag">&lt;<span class="name">orderEntry</span> <span class="attr">type</span>=<span class="string">&quot;module-library&quot;</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">library</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">CLASSES</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">root</span> <span class="attr">url</span>=<span class="string">&quot;jar://C:/Program Files/Java/jdk1.8.0_251/lib/tools.jar!/&quot;</span> /&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">CLASSES</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">JAVADOC</span> /&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">SOURCES</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">root</span> <span class="attr">url</span>=<span class="string">&quot;jar://C:/Program Files/Java/jdk1.8.0_251/lib/tools.jar!/&quot;</span> /&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">SOURCES</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">library</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">orderEntry</span>&gt;</span></span><br></pre></td></tr></table></figure><p>当然，你也可以通过Intellij IDEA右上角的“Project Structure”或快捷键”Ctrl+Alt+Shift+S“打开Project Structure配置面板。选中”Project Settings“-&gt;”Modules“，然后选中你需要引入tools.jar的module,然后在右侧上方的tab选项卡中选中“Dependencies“-&gt;”Add”-&gt;“1 JARs or directories…”，然后选择JDK8安装目录下的tools.jar即完成依赖包的引入。如下图：<br><img src="https://img.klavor.com/2021/01/20210129-1001-001.png" alt="「解决方案」JDK11环境下的Android/Java项目中导入tools.jar包依赖"></p><h3 id="JDK11-amp-Gradle"><a href="#JDK11-amp-Gradle" class="headerlink" title="JDK11 &amp; Gradle"></a>JDK11 &amp; Gradle</h3><p>修改项目下的build.gradle文件，添加sourceCompatibility和targetCompatibility。</p><figure class="highlight gradle"><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">java &#123;</span><br><span class="line">    <span class="keyword">sourceCompatibility</span> = JavaVersion.VERSION_1_8</span><br><span class="line">    <span class="keyword">targetCompatibility</span> = JavaVersion.VERSION_1_8</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">dependencies</span> &#123;</span><br><span class="line"><span class="comment">//    implementation files(&#x27;C:\\Program Files\\Java\\jdk1.8.0_251\\lib\\tools.jar&#x27;)</span></span><br><span class="line"><span class="comment">//    implementation files(System.getenv(&#x27;JAVA_HOME&#x27;) + &#x27;/lib/tools.jar&#x27;)</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>顺便提一嘴，Android Studio中的Java Module配置和此一样。</p><h3 id="JDK11-amp-Java"><a href="#JDK11-amp-Java" class="headerlink" title="JDK11 &amp; Java"></a>JDK11 &amp; Java</h3><p>将项目根目录下的.iml从<code>&lt;orderEntry type=&quot;inheritedJdk&quot; /&gt;</code>修改成<code>&lt;orderEntry type=&quot;jdk&quot; jdkName=&quot;8&quot; jdkType=&quot;JavaSDK&quot; /&gt;</code>。如下图:<br><img src="https://img.klavor.com/2021/01/20210129-1001-002.png" alt="「解决方案」JDK11环境下的Android/Java项目中导入tools.jar包依赖"></p><p>或者通过Project Structure面板进行修改同样可行。<br><img src="https://img.klavor.com/2021/01/20210129-1001-003.png" alt="「解决方案」JDK11环境下的Android/Java项目中导入tools.jar包依赖"></p><h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><p>综上所述，其实配置方式挺简单的。以上也是个人开发中遇到并寻求解决方案过程中得到的结果。JDK9之后，像tools.jar、dt.jar等JDK安装目录中lib下的jar包都被移除了。相应的，增加了jmods文件夹，文件夹下jdk.compiler.jmod对应着之前的tools.jar。使用解压软件打开jdk.compiler.jmod，可以发现jdk.compiler.jmod中的classes目录下的文件和tools.jar几乎是一样的，oracle将其分模块进行隔离，旨在提高其安全性等方面原因。而之所以使用JDK11时在项目中配置目标版本为8时，就可以使用其中的诸如tools.jar包里面的类，我想是为了兼容可能吧。<br>如有疑问/建议，可以给我留言，我们共同成长！</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;首先，来说一下今天写这篇文章的目的。从JDK9开始，JDK安装包中就不再包含tools.jar包了，那么之前所使用的依赖方式就失效了，那么我们应该如何在新版本中去解决这个以来问题，从而不影响我们的项目正常编译呢？&lt;br&gt;在开发时，我们可能会在编译前或编译后通过一些手段去修改</summary>
      
    
    
    
    <category term="dev" scheme="https://www.klavor.com/categories/dev/"/>
    
    
    <category term="Android" scheme="https://www.klavor.com/tags/Android/"/>
    
    <category term="Java" scheme="https://www.klavor.com/tags/Java/"/>
    
    <category term="解决方案" scheme="https://www.klavor.com/tags/%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88/"/>
    
    <category term="Gradle" scheme="https://www.klavor.com/tags/Gradle/"/>
    
    <category term="依赖包" scheme="https://www.klavor.com/tags/%E4%BE%9D%E8%B5%96%E5%8C%85/"/>
    
  </entry>
  
  <entry>
    <title>正式从Wordpress迁移至Hexo并恢复更新</title>
    <link href="https://www.klavor.com/essay/20210127-1000.html"/>
    <id>https://www.klavor.com/essay/20210127-1000.html</id>
    <published>2021-01-26T16:00:00.000Z</published>
    <updated>2025-11-01T00:45:46.348Z</updated>
    
    <content type="html"><![CDATA[<p>转眼2020年就结束了，这一年博客处于停更状态，更有甚处于闭站状态。主要原因还是投入产出比不高。<br>从2012年注册第一个域名开始，就做了淘宝客、导航、论坛和博客等多种类型的网站。但是没有一条是能长期走下去的。域名中途也换了一波又一波，从lihuan.com.cn到stiky.me，再到codog.net，最后到klavor.com。期间还有一些没有使用上而放弃续费的域名，如hellown.com、dopo.io、woo.st、an-droid.ren等五花八门的域名。<br>最主要的原因还是因为没有什么特别有价值的内容可以做，或者说是没有发掘到有价值的内容来做。早年的淘宝客网站做的刚起步，淘宝联盟就更改了搜索规则，必须要进行淘宝站内搜索，于是导致这条路也不好走了，最终选择了放弃，并投入到博客类网站的建设中。<br>由于博客类网站没有比较大的流量，百度联盟的广告收录也少的可怜。甚至现在新申请的域名连开通广告的权限的没有。加上购买服务器的费用，每年都只有支出，却连微薄的一点收入都没有。考虑再三，最终决定切换到Hexo，并使用现在的github和coding这些支持pages的平台来进行建站，以压缩成本，等到有明确的目标再考虑购入新的云服务器。<br>但是没有云服务器又存在一个问题。之前写的必应每日一图的脚本就没地方执行了，之后可能还得想办法让脚本跑起来。这也是一个不错的引流手段。<br>这次切换到Hexo之后，将将更多的时间用于写博客而不是研究各种花里胡哨的功能。之前使用wordpress时，花了大量的时间在主题和插件上了，以至于真正的内容都几乎没有。<br>2021年，牛气冲天的一年!</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;转眼2020年就结束了，这一年博客处于停更状态，更有甚处于闭站状态。主要原因还是投入产出比不高。&lt;br&gt;从2012年注册第一个域名开始，就做了淘宝客、导航、论坛和博客等多种类型的网站。但是没有一条是能长期走下去的。域名中途也换了一波又一波，从lihuan.com.cn到st</summary>
      
    
    
    
    <category term="essay" scheme="https://www.klavor.com/categories/essay/"/>
    
    
    <category term="Wordpress" scheme="https://www.klavor.com/tags/Wordpress/"/>
    
    <category term="Hexo" scheme="https://www.klavor.com/tags/Hexo/"/>
    
  </entry>
  
  <entry>
    <title>「代码评审」Gerrit remote rejected no new changes error：failed to push some refs to 错误的解决办法</title>
    <link href="https://www.klavor.com/dev/20190822-631.html"/>
    <id>https://www.klavor.com/dev/20190822-631.html</id>
    <published>2019-08-21T16:00:00.000Z</published>
    <updated>2025-11-01T00:45:46.341Z</updated>
    
    <content type="html"><![CDATA[<p>因为公司代码评审使用的是gerrit，而今天提交代码到gerrit时报了如下的错误：</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><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">Enumerating objects: 17, done.</span><br><span class="line">Counting objects: 100% (17/17), done.</span><br><span class="line">Delta compression using up to 8 threads</span><br><span class="line">Compressing objects: 100% (7/7), done.</span><br><span class="line">Writing objects: 100% (9/9), 961 bytes | 480.00 KiB/s, done.</span><br><span class="line">Total 9 (delta 5), reused 0 (delta 0)</span><br><span class="line">remote: Resolving deltas: 100% (5/5)</span><br><span class="line">remote: Processing changes: refs: 1, done</span><br><span class="line">To ssh://gerrit.devlang.org:9999/app/android-framewark</span><br><span class="line"> ! [remote rejected]     HEAD -&gt; refs/for/dev (no new changes)</span><br><span class="line">error: failed to push some refs to &#x27;ssh://klavor@gerrit.devlang.org:9999/app/android-framewark&#x27;</span><br></pre></td></tr></table></figure><p>试了很多次之后发现依旧报了同样的错误。<br>后来登录到了gerrit上查看提交记录，发现commit已经成功push上去了。所以导致这个报错的原因是gerrit上已经包含了具有同样commitid的提交了，如果你确认这个具有相同commitid的提交不是同一笔（一般不会出现），可以通过<code>git commit --amend</code>打开commit mesage编辑状态，然后不需要修改任何东西，然后输入<code>:wq</code>保存退出，这个时候commitid就发生了变化了，这时再提交应该就没有问题了，如果还是报了同样的错误，肯定是这次提交已经存在了，从错误提示里的no new changes可以看出，更改后的内容和gerrit里的是一致的，不需要再次提交。<br>如果还有疑问可以在下方评论区留言。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;因为公司代码评审使用的是gerrit，而今天提交代码到gerrit时报了如下的错误：&lt;/p&gt;
&lt;figure class=&quot;highlight plaintext&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;</summary>
      
    
    
    
    <category term="dev" scheme="https://www.klavor.com/categories/dev/"/>
    
    
    <category term="解决方案" scheme="https://www.klavor.com/tags/%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88/"/>
    
    <category term="代码评审" scheme="https://www.klavor.com/tags/%E4%BB%A3%E7%A0%81%E8%AF%84%E5%AE%A1/"/>
    
    <category term="Gerrit" scheme="https://www.klavor.com/tags/Gerrit/"/>
    
    <category term="Code Review" scheme="https://www.klavor.com/tags/Code-Review/"/>
    
  </entry>
  
  <entry>
    <title>「安卓开发」Android防爆力点击事件处理解决方法及其存在的问题</title>
    <link href="https://www.klavor.com/dev/20190821-629.html"/>
    <id>https://www.klavor.com/dev/20190821-629.html</id>
    <published>2019-08-20T16:00:00.000Z</published>
    <updated>2025-11-01T00:45:46.341Z</updated>
    
    <content type="html"><![CDATA[<p>Android中防爆力点击很多App中都会用到，但是我看过几个项目中的源码，大部分都是使用的System.currentTimeMillis()来获取当前时间与上一次点击时间间隔来做防暴力点击处理。<br>但是问题来了，由于System.currentTimeMillis()获取的是系统时间，这个时间会根据手机设置的时间而变化，那么就会导致一种情况，即当用户点击了一个View后记录了上一次的点击时间戳，这时将时间往前调之后，下一次再点击时System.currentTimeMillis()获取到的时间戳是比上一次点击时间戳要小的，因此就会导致点击无响应的情况发生。虽然说，这种情况几乎不会发生，或者发生了影响也不会太大，但是既然是一个问题，并且可以找到其他解决的方法，那么为什么不使用更优的方式来计算处理点击事件的时间间隔呢。<br>如下的代码中使用到了几种计算点击事件时间间隔的方式：</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><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">package org.devlang.demo.click;</span><br><span class="line"></span><br><span class="line">import android.os.SystemClock;</span><br><span class="line">import android.util.Log;</span><br><span class="line">import android.view.View;</span><br><span class="line"></span><br><span class="line">import java.util.Calendar;</span><br><span class="line"></span><br><span class="line">public abstract class OnThrottleClickListener implements View.OnClickListener &#123;</span><br><span class="line">    private static final int THROTTLE_CLICK_GAP_TIME = 300;</span><br><span class="line">    private long preClickTime;</span><br><span class="line"></span><br><span class="line">    @Override</span><br><span class="line">    public void onClick(View view) &#123;</span><br><span class="line">//        long currentTimeMillis = System.currentTimeMillis();</span><br><span class="line">//        long currentTimeMillis = Calendar.getInstance().getTimeInMillis();</span><br><span class="line">        long currentTimeMillis = SystemClock.uptimeMillis();</span><br><span class="line">//        long currentTimeMillis = SystemClock.elapsedRealtime();</span><br><span class="line">        if (currentTimeMillis - preClickTime &gt; THROTTLE_CLICK_GAP_TIME) &#123;</span><br><span class="line">            onThrottleClick(view);</span><br><span class="line">            preClickTime = currentTimeMillis;</span><br><span class="line">            Log.d(&quot;cmf&quot;, &quot;perform&quot;);</span><br><span class="line">        &#125; else &#123;</span><br><span class="line">            Log.d(&quot;cmf&quot;, &quot;break&quot;);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    public abstract void onThrottleClick(View view);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ul><li>System.currentTimeMillis() 系统时间，会根据手机系统中设置的时间改变；</li><li>Calendar.getInstance().getTimeInMillis() 这种方式是最low的。因为每次点击都会创建一个Calendar实例，在后端开发中，都是拒绝使用这个类的，因为效率会比较低。</li><li>SystemClock.uptimeMillis() 自开机后，经过的时间，不包括深度睡眠的时间。Looper中所使用的也是这个方法，对时间间隔的计算比较有保证。</li><li>SystemClock.elapsedRealtime() 自开机后，经过的时间，包括深度睡眠的时间。</li></ul><p>这也是之前开发中遇到的问题，虽然影响不大，但也可以注意一下这个问题。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;Android中防爆力点击很多App中都会用到，但是我看过几个项目中的源码，大部分都是使用的System.currentTimeMillis()来获取当前时间与上一次点击时间间隔来做防暴力点击处理。&lt;br&gt;但是问题来了，由于System.currentTimeMillis(</summary>
      
    
    
    
    <category term="dev" scheme="https://www.klavor.com/categories/dev/"/>
    
    
    <category term="Android" scheme="https://www.klavor.com/tags/Android/"/>
    
    <category term="解决方案" scheme="https://www.klavor.com/tags/%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88/"/>
    
    <category term="防暴力点击" scheme="https://www.klavor.com/tags/%E9%98%B2%E6%9A%B4%E5%8A%9B%E7%82%B9%E5%87%BB/"/>
    
    <category term="安卓开发" scheme="https://www.klavor.com/tags/%E5%AE%89%E5%8D%93%E5%BC%80%E5%8F%91/"/>
    
  </entry>
  
  <entry>
    <title>「Nginx」CentOS下修改Nginx配置指定文件路径</title>
    <link href="https://www.klavor.com/dev/20190724-581.html"/>
    <id>https://www.klavor.com/dev/20190724-581.html</id>
    <published>2019-07-23T16:00:00.000Z</published>
    <updated>2025-11-01T00:45:46.341Z</updated>
    
    <content type="html"><![CDATA[<h3 id="安装编辑工具"><a href="#安装编辑工具" class="headerlink" title="安装编辑工具"></a>安装编辑工具</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">yum install vim</span><br></pre></td></tr></table></figure><p>博主这里选择vim而不是vi是有原因的。因为在使用过程中，vi总是有些莫名其妙的问题，体验不太好，而vim不仅符合正常的使用习惯，而且内容还会高亮显示，看代码可不要太舒服。</p><h3 id="编辑nginx-conf"><a href="#编辑nginx-conf" class="headerlink" title="编辑nginx.conf"></a>编辑nginx.conf</h3><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><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></pre></td><td class="code"><pre><span class="line">#user  nobody;</span><br><span class="line">worker_processes  1;</span><br><span class="line"></span><br><span class="line">#error_log  logs/error.log;</span><br><span class="line">#error_log  logs/error.log  notice;</span><br><span class="line">#error_log  logs/error.log  info;</span><br><span class="line"></span><br><span class="line">#pid        logs/nginx.pid;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">events &#123;</span><br><span class="line">    worker_connections  1024;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">http &#123;</span><br><span class="line">    include       mime.types;</span><br><span class="line">    default_type  application/octet-stream;</span><br><span class="line"></span><br><span class="line">    #log_format  main  &#x27;$remote_addr - $remote_user [$time_local] &quot;$request&quot; &#x27;</span><br><span class="line">    #                  &#x27;$status $body_bytes_sent &quot;$http_referer&quot; &#x27;</span><br><span class="line">    #                  &#x27;&quot;$http_user_agent&quot; &quot;$http_x_forwarded_for&quot;&#x27;;</span><br><span class="line"></span><br><span class="line">    #access_log  logs/access.log  main;</span><br><span class="line"></span><br><span class="line">    sendfile        on;</span><br><span class="line">    #tcp_nopush     on;</span><br><span class="line"></span><br><span class="line">    #keepalive_timeout  0;</span><br><span class="line">    keepalive_timeout  65;</span><br><span class="line"></span><br><span class="line">    #gzip  on;</span><br><span class="line"></span><br><span class="line">    server &#123;</span><br><span class="line">        listen       80;</span><br><span class="line">        server_name  localhost;</span><br><span class="line"></span><br><span class="line">        #charset koi8-r;</span><br><span class="line"></span><br><span class="line">        #access_log  logs/host.access.log  main;</span><br><span class="line"></span><br><span class="line">        location / &#123;</span><br><span class="line">            root   /www;</span><br><span class="line">            index  index.html index.htm;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        #error_page  404              /404.html;</span><br><span class="line"></span><br><span class="line">        # redirect server error pages to the static page /50x.html</span><br><span class="line">        #</span><br><span class="line">        error_page   500 502 503 504  /50x.html;</span><br><span class="line">        location = /50x.html &#123;</span><br><span class="line">            root   /www;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        # proxy the PHP scripts to Apache listening on 127.0.0.1:80</span><br><span class="line">        #</span><br><span class="line">        #location ~ \.php$ &#123;</span><br><span class="line">        #    proxy_pass   http://127.0.0.1;</span><br><span class="line">        #&#125;</span><br><span class="line"></span><br><span class="line">        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000</span><br><span class="line">        #</span><br><span class="line">        #location ~ \.php$ &#123;</span><br><span class="line">        #    root           html;</span><br><span class="line">        #    fastcgi_pass   127.0.0.1:9000;</span><br><span class="line">        #    fastcgi_index  index.php;</span><br><span class="line">        #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;</span><br><span class="line">        #    include        fastcgi_params;</span><br><span class="line">        #&#125;</span><br><span class="line"></span><br><span class="line">        # deny access to .htaccess files, if Apache&#x27;s document root</span><br><span class="line">        # concurs with nginx&#x27;s one</span><br><span class="line">        #</span><br><span class="line">        #location ~ /\.ht &#123;</span><br><span class="line">        #    deny  all;</span><br><span class="line">        #&#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    # another virtual host using mix of IP-, name-, and port-based configuration</span><br><span class="line">    #</span><br><span class="line">    #server &#123;</span><br><span class="line">    #    listen       8000;</span><br><span class="line">    #    listen       somename:8080;</span><br><span class="line">    #    server_name  somename  alias  another.alias;</span><br><span class="line"></span><br><span class="line">    #    location / &#123;</span><br><span class="line">    #        root   html;</span><br><span class="line">    #        index  index.html index.htm;</span><br><span class="line">    #    &#125;</span><br><span class="line">    #&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    # HTTPS server</span><br><span class="line">    #</span><br><span class="line">    #server &#123;</span><br><span class="line">    #    listen       443 ssl;</span><br><span class="line">    #    server_name  localhost;</span><br><span class="line"></span><br><span class="line">    #    ssl_certificate      cert.pem;</span><br><span class="line">    #    ssl_certificate_key  cert.key;</span><br><span class="line"></span><br><span class="line">    #    ssl_session_cache    shared:SSL:1m;</span><br><span class="line">    #    ssl_session_timeout  5m;</span><br><span class="line"></span><br><span class="line">    #    ssl_ciphers  HIGH:!aNULL:!MD5;</span><br><span class="line">    #    ssl_prefer_server_ciphers  on;</span><br><span class="line"></span><br><span class="line">    #    location / &#123;</span><br><span class="line">    #        root   html;</span><br><span class="line">    #        index  index.html index.htm;</span><br><span class="line">    #    &#125;</span><br><span class="line">    #&#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>通过修改location里面的root指定nginx的根路径，在前篇<a href="https://www.klavor.com/dev/20190723-579.html">「Nginx」CentOS7.6操作系统下通过源码安装Nginx教程</a>中，新增了名为www的用户并为其指定了目录/www，因此这里将root设置为/www。</p><h3 id="测试效果"><a href="#测试效果" class="headerlink" title="测试效果"></a>测试效果</h3><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">cd /www</span><br><span class="line">vim index.html</span><br></pre></td></tr></table></figure><p>进入到目录/www中并创建名为index.html的文件。</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><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">&lt;html&gt;</span><br><span class="line">&lt;head&gt;</span><br><span class="line">    &lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html;charset=utf-8&quot;&gt;</span><br><span class="line">    &lt;title&gt;网站正在建设中...&lt;/title&gt;</span><br><span class="line">&lt;/head&gt;</span><br><span class="line">&lt;body&gt;</span><br><span class="line">&lt;a href=&quot;https://www.klavor.com&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;网站正在建设中...&lt;/a&gt;</span><br><span class="line">&lt;/body&gt;</span><br><span class="line">&lt;/html&gt;</span><br></pre></td></tr></table></figure><p>编辑index.html文件的内容，保存并退出。最后查看页面效果如下：</p><p><img src="https://img.klavor.com/2019/07/2019072316112168.png" alt="「Nginx」CentOS下修改Nginx配置指定文件路径"></p>]]></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;figure class=&quot;highlight plaintext&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=</summary>
      
    
    
    
    <category term="dev" scheme="https://www.klavor.com/categories/dev/"/>
    
    
    <category term="Linux" scheme="https://www.klavor.com/tags/Linux/"/>
    
    <category term="Nginx" scheme="https://www.klavor.com/tags/Nginx/"/>
    
    <category term="CentOS" scheme="https://www.klavor.com/tags/CentOS/"/>
    
    <category term="文件配置" scheme="https://www.klavor.com/tags/%E6%96%87%E4%BB%B6%E9%85%8D%E7%BD%AE/"/>
    
  </entry>
  
  <entry>
    <title>「Nginx」CentOS7.6操作系统下通过源码安装Nginx问题汇总</title>
    <link href="https://www.klavor.com/dev/20190724-586.html"/>
    <id>https://www.klavor.com/dev/20190724-586.html</id>
    <published>2019-07-23T16:00:00.000Z</published>
    <updated>2025-11-01T00:45:46.341Z</updated>
    
    <content type="html"><![CDATA[<h4 id="没有配置pcre库"><a href="#没有配置pcre库" class="headerlink" title="没有配置pcre库"></a>没有配置pcre库</h4><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">./configure: error: the HTTP rewrite module requires the PCRE library.</span><br><span class="line">You can either disable the module by using --without-http_rewrite_module</span><br><span class="line">option, or install the PCRE library into the system, or build the PCRE library</span><br><span class="line">statically from the source with nginx by using --with-pcre=&lt;path&gt; option.</span><br></pre></td></tr></table></figure><p>可以通过安装pcre库或者通过配置项–with-pcre指定pcre库源码路径来解决此问题。如果不需要启用此模块，则可以使用配置项–without-http_rewrite_module声明不启用HttpRewrite模块。</p><h4 id="没有配置zlib库"><a href="#没有配置zlib库" class="headerlink" title="没有配置zlib库"></a>没有配置zlib库</h4><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">./configure: error: the HTTP gzip module requires the zlib library.</span><br><span class="line">You can either disable the module by using --without-http_gzip_module</span><br><span class="line">option, or install the zlib library into the system, or build the zlib library</span><br><span class="line">statically from the source with nginx by using --with-zlib=&lt;path&gt; option.</span><br></pre></td></tr></table></figure><p>可以通过安装zlib库或者通过配置项–with-zlib指定zlib库源码路径来解决此问题。如果不需要启用此模块，则可以使用配置项–without-http_gzip_module声明不启用Gzip模块。</p><h4 id="没有配置openssl库"><a href="#没有配置openssl库" class="headerlink" title="没有配置openssl库"></a>没有配置openssl库</h4><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">./configure: error: SSL modules require the OpenSSL library.</span><br><span class="line">You can either do not enable the modules, or install the OpenSSL library</span><br><span class="line">into the system, or build the OpenSSL library statically from the source</span><br><span class="line">with nginx by using --with-openssl=&lt;path&gt; option.</span><br></pre></td></tr></table></figure><p>nginx默认是不启用HttpSsl模块的，如果在配置中指定了–with-http_ssl_module，则需要安装openssl库或者通过配置项–with-openssl指定openssl库源码路径来解决此问题。</p><h4 id="指定的库路径不正确"><a href="#指定的库路径不正确" class="headerlink" title="指定的库路径不正确"></a>指定的库路径不正确</h4><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><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">make -f objs/Makefile</span><br><span class="line">make[1]: Entering directory `/root/nginx-1.17.1&#x27;</span><br><span class="line">cd ~/pcre-8.43 \</span><br><span class="line">&amp;&amp; if [ -f Makefile ]; then make distclean; fi \</span><br><span class="line">&amp;&amp; CC=&quot;cc&quot; CFLAGS=&quot;-O2 -fomit-frame-pointer -pipe &quot; \</span><br><span class="line">./configure --disable-shared </span><br><span class="line">/bin/sh: line 0: cd: /root/pcre-8.43: No such file or directory</span><br><span class="line">make[1]: *** [/root/pcre-8.43/Makefile] Error 1</span><br><span class="line">make[1]: Leaving directory `/root/nginx-1.17.1&#x27;</span><br><span class="line">make: *** [build] Error 2</span><br></pre></td></tr></table></figure><p>终端输入<strong>make &amp;&amp; make install</strong>后，出现了以上错误。根据错误提示内容中的**/root/pcre-8.43: No such file or directory<strong>可以看出这个路径是不存在的。通过</strong>ls /root**发现确实是不存在此文件，因此需要重新在终端中使用./configure并重新配置相应的正确路径。</p><h4 id="无效编译器"><a href="#无效编译器" class="headerlink" title="无效编译器"></a>无效编译器</h4><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">configure: error: Invalid C++ compiler or C++ compiler flags</span><br><span class="line">make[1]: *** [/root/pcre-8.43/Makefile] Error 1</span><br><span class="line">make[1]: Leaving directory `/root/nginx-1.17.1&#x27;</span><br><span class="line">make: *** [build] Error 2</span><br></pre></td></tr></table></figure><p>根据错误提示可以看出，编译的时候没有找到合适的编译器。可以通过**yum install gcc gcc-c++**安装编译时需要的编译器。</p><h4 id="找不到openssl-ssl-h文件"><a href="#找不到openssl-ssl-h文件" class="headerlink" title="找不到openssl/ssl.h文件"></a>找不到openssl/ssl.h文件</h4><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><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">In file included from src/core/ngx_core.h:83:0,</span><br><span class="line">                 from src/core/nginx.c:9:</span><br><span class="line">src/event/ngx_event_openssl.h:15:25: fatal error: openssl/ssl.h: No such file or directory</span><br><span class="line"> #include &lt;openssl/ssl.h&gt;</span><br><span class="line">                         ^</span><br><span class="line">compilation terminated.</span><br><span class="line">make[1]: *** [objs/src/core/nginx.o] Error 1</span><br><span class="line">make[1]: Leaving directory `/root/nginx-1.17.1&#x27;</span><br><span class="line">make: *** [build] Error 2</span><br></pre></td></tr></table></figure><p>这个错误比较神奇，我也没进行深究，只是在./configure阶段使用的~/XXX作为路径配置了–with-openssl的配置项。出现这个问题后，我把nginx源码的文件夹统统删掉后，重新解压后将–with-openssl配置为绝对路径后就没问题了。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h4 id=&quot;没有配置pcre库&quot;&gt;&lt;a href=&quot;#没有配置pcre库&quot; class=&quot;headerlink&quot; title=&quot;没有配置pcre库&quot;&gt;&lt;/a&gt;没有配置pcre库&lt;/h4&gt;&lt;figure class=&quot;highlight plaintext&quot;&gt;&lt;table&gt;&lt;t</summary>
      
    
    
    
    <category term="dev" scheme="https://www.klavor.com/categories/dev/"/>
    
    
    <category term="Linux" scheme="https://www.klavor.com/tags/Linux/"/>
    
    <category term="Nginx" scheme="https://www.klavor.com/tags/Nginx/"/>
    
    <category term="CentOS" scheme="https://www.klavor.com/tags/CentOS/"/>
    
    <category term="源码安装" scheme="https://www.klavor.com/tags/%E6%BA%90%E7%A0%81%E5%AE%89%E8%A3%85/"/>
    
    <category term="问题汇总" scheme="https://www.klavor.com/tags/%E9%97%AE%E9%A2%98%E6%B1%87%E6%80%BB/"/>
    
  </entry>
  
  <entry>
    <title>「Nginx」CentOS7.6操作系统下通过源码安装Nginx教程</title>
    <link href="https://www.klavor.com/dev/20190723-579.html"/>
    <id>https://www.klavor.com/dev/20190723-579.html</id>
    <published>2019-07-22T16:00:00.000Z</published>
    <updated>2025-09-25T02:33:37.821Z</updated>
    
    <content type="html"><![CDATA[<h3 id="准备工作"><a href="#准备工作" class="headerlink" title="准备工作"></a>准备工作</h3><h4 id="服务器"><a href="#服务器" class="headerlink" title="服务器"></a>服务器</h4><p>由于只是为了演示，因此这里选用的服务器是阿里云的抢占式实例，优点是价格低，配置高，适合超短期内的需求。比如博主基本上就使用一两个小时就释放了，也就花了两毛不到。</p><p>&gt; 计费方式 ： 抢占式实例<br>&gt; 地域 ： 华南1 可用区 E<br>&gt; 实例 ： 计算型 c5 / ecs.c5.large(2vCPU 4GiB)<br>&gt; 单台实例规格上限价格 ： ￥ 0.62<br>&gt; 购买数量 ： 1 台<br>&gt; 镜像 ： CentOS 7.6 64位(安全加固)<br>&gt; 系统盘 ： 高效云盘 40GiB</p><h4 id="源码安装包"><a href="#源码安装包" class="headerlink" title="源码安装包"></a>源码安装包</h4><p><a href="http://nginx.org/">nginx</a>：<a href="http://nginx.org/download/nginx-1.17.1.tar.gz">http://nginx.org/download/nginx-1.17.1.tar.gz</a><br><a href="http://www.pcre.org/">pcre</a>：<a href="ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/pcre-8.43.tar.gz">ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/pcre-8.43.tar.gz</a><br><a href="http://www.zlib.net/">zlib</a>：<a href="http://www.zlib.net/zlib-1.2.11.tar.gz">http://www.zlib.net/zlib-1.2.11.tar.gz</a><br><a href="https://www.openssl.org/">openssl</a>：<a href="https://www.openssl.org/source/openssl-1.0.2s.tar.gz">https://www.openssl.org/source/openssl-1.0.2s.tar.gz</a></p><h3 id="安装步骤"><a href="#安装步骤" class="headerlink" title="安装步骤"></a>安装步骤</h3><p><strong>1.创建nginx用户</strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">useradd www -d /www</span><br></pre></td></tr></table></figure><p>其中，www为用户名，linux默认会为其创建一个名为www的用户组；/www为用户的目录，此目录之后会用于存放前端文件。</p><p><strong>2.安装编译环境</strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">yum install gcc gcc-c++</span><br></pre></td></tr></table></figure><p>通过此命令行安装编译工具。</p><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><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><br><span class="line">cd ~</span><br><span class="line">//下载nginx源码安装包</span><br><span class="line">wget http://nginx.org/download/nginx-1.17.1.tar.gz</span><br><span class="line">//下载zlib源码安装包</span><br><span class="line">wget http://www.zlib.net/zlib-1.2.11.tar.gz</span><br><span class="line">//下载pcre源码安装包</span><br><span class="line">wget ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/pcre-8.43.tar.gz</span><br><span class="line">//下载openssl源码安装包</span><br><span class="line">wget https://www.openssl.org/source/openssl-1.0.2s.tar.gz</span><br></pre></td></tr></table></figure><p>以上代码逐行执行，将源码安装包下载到服务器中。如果想要获取最新源码安装包的地址，可以在<strong>准备工作</strong>里的<strong>源码安装包</strong>中提示的官网里找到最新的对应源码安装包下载地址。</p><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></pre></td><td class="code"><pre><span class="line">tar -zxvf nginx-1.17.1.tar.gz</span><br><span class="line">tar -zxvf pcre-8.43.tar.gz</span><br><span class="line">tar -zxvf zlib-1.2.11.tar.gz</span><br><span class="line">tar -zxvf openssl-1.0.2s.tar.gz</span><br></pre></td></tr></table></figure><p>通过tar命令将压缩包解压到当前目录下。</p><p><strong>5.配置nginx</strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">./configure --prefix=/env/nginx --user=www --group=www --with-pcre=../pcre-8.43 --with-zlib=../zlib-1.2.11 --with-http_ssl_module --with-openssl=../openssl-1.0.2s</span><br></pre></td></tr></table></figure><p><strong>–prefix</strong> nginx安装路径，路径是/env/nginx。<br><strong>–user</strong> nginx用户，用户是www。<br><strong>–group</strong> nginx用户组，用户组是www。<br><strong>–with-pcre</strong> nginx使用的pcre库，用于请求重定向，nginx默认编译。如果不开启可以将配置替换成–without-http_rewrite_module<br><strong>–with-zlib</strong> nginx使用的zlib库，用于压缩网页页面内容，ngin默认编译。如果不开启可以将配置替换成–without-http_gzip_module<br><strong>–with-http_ssl_module</strong> 开启ssl支持，nginx默认不编译。<br><strong>–with-openssl</strong> nginx使用的openssl库。如果不需要则去掉配置–with-http_ssl_module即可。</p><p>需要注意的一点是，这里配置的路径为../XXX是因为之前解压的时候将几个压缩包解压到同级目录下，如果不熟悉相对路径的童鞋可以使用绝对路径进行配置。<br>另外，更多配置可以到官方网站自行查阅。<a href="http://nginx.org/en/docs/configure.html">http://nginx.org/en/docs/configure.html</a></p><p><strong>6.编译安装nginx</strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">make &amp;amp;&amp;amp; make install</span><br></pre></td></tr></table></figure><p>这就不需要多说了，模板代码。</p><h3 id="启动nginx服务"><a href="#启动nginx服务" class="headerlink" title="启动nginx服务"></a>启动nginx服务</h3><p>完成以上安装步骤之后，直接在终端输入nginx是启动不了nginx服务的，所以需要将nginx命令复制到/usr/bin中。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ln /env/nginx/sbin/nginx /usr/bin</span><br></pre></td></tr></table></figure><p>通过在/usr/bin中创建一个nginx的硬链接，这样就可以不管在什么路径下都可以直接使用nginx命令启动服务了。</p><p><img src="https://img.klavor.com/2019/07/2019072316151982.png" alt="「Nginx」CentOS7.6操作系统下通过源码安装Nginx教程"></p><h3 id="停止和重启nginx服务"><a href="#停止和重启nginx服务" class="headerlink" title="停止和重启nginx服务"></a>停止和重启nginx服务</h3><p>这里使用比较笨的方式进行重启。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ps -C nginx</span><br></pre></td></tr></table></figure><p>通过以上命令查找当前nginx的pid。</p><p>&gt; [root@iZwz9cm3r1qylcc4dh7n2wZ ~]# ps -C nginx<br>&gt; PID TTY TIME CMD<br>&gt; 14414 ? 00:00:00 nginx<br>&gt; 14415 ? 00:00:00 nginx</p><p>然后通过kill命令进行停止</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">kill -QUIT 14414</span><br></pre></td></tr></table></figure><p>一般情况下只需要杀死第一个进程就都会关闭了。如果有问题就两个都kill掉。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">nginx</span><br></pre></td></tr></table></figure><p>最后再直接在终端输入nginx命令启动nginx服务即可完成重启。</p><h3 id="简单方式"><a href="#简单方式" class="headerlink" title="简单方式"></a>简单方式</h3><p>另外，在CentOS系统中，可以通过yum命令简单快捷的安装nginx服务。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">yum install nginx</span><br></pre></td></tr></table></figure><p>可以根据个人爱好自行选择安装方式。yum方式安装成功后的默认效果图如下：</p><p><img src="https://img.klavor.com/2019/07/2019072316160780.png" alt="「Nginx」CentOS7.6操作系统下通过源码安装Nginx教程"></p><p><a href="https://www.klavor.com/dev/20190724-586.html">「Nginx」CentOS7.6操作系统下通过源码安装Nginx问题汇总</a></p>]]></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;h4 id=&quot;服务器&quot;&gt;&lt;a href=&quot;#服务器&quot; class=&quot;headerlink&quot; title=&quot;服务器&quot;&gt;&lt;/a&gt;服务</summary>
      
    
    
    
    <category term="dev" scheme="https://www.klavor.com/categories/dev/"/>
    
    
    <category term="Linux" scheme="https://www.klavor.com/tags/Linux/"/>
    
    <category term="Nginx" scheme="https://www.klavor.com/tags/Nginx/"/>
    
    <category term="CentOS" scheme="https://www.klavor.com/tags/CentOS/"/>
    
    <category term="阿里云" scheme="https://www.klavor.com/tags/%E9%98%BF%E9%87%8C%E4%BA%91/"/>
    
    <category term="源码安装" scheme="https://www.klavor.com/tags/%E6%BA%90%E7%A0%81%E5%AE%89%E8%A3%85/"/>
    
  </entry>
  
  <entry>
    <title>「算法原理」CRC检验算法原理及其Java实现</title>
    <link href="https://www.klavor.com/dev/20190618-552.html"/>
    <id>https://www.klavor.com/dev/20190618-552.html</id>
    <published>2019-06-17T16:00:00.000Z</published>
    <updated>2025-11-01T00:45:46.341Z</updated>
    
    <content type="html"><![CDATA[<h3 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h3><p>这段时间处于待业状态中，所以就自己捣鼓些东西，学习学习有趣的算法。因为对于文件的校验可以通过CRC、SHA和MD5等方式进行，所以有了一个想法，做一个文件校验的网站和应用，提供一套服务给广大用户校验文件的正确性。<br>因此，对于这几种校验的算法，当然要了解一下，于是从CRC开始着手。想起当初学习base64编码的时候，感觉这些算法还是挺有意思的，可以玩弄一番，虽然对就业帮助并不是很大。<br>这篇文章主要是记录一下查阅过的参考博客以及用java实现CRC校验算法。</p><h3 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h3><p><a href="https://baike.baidu.com/item/CRC%E6%A0%A1%E9%AA%8C/3439037?fr=aladdin">CRC检验算法原理</a><br><a href="http://www.eeworld.com.cn/qrs/2015/1013/article_25149.html">CRC校验原理与程序设计——(RS485总线系统应用之1)</a><br><a href="https://blog.csdn.net/u013898698/article/details/78864161">CRC32校验原理及实现</a><br><a href="https://blog.csdn.net/slimmm/article/details/88576296">CRC8/CRC16/CRC32常见几个标准的算法及C语言实现</a></p><h3 id="常见CRC参数模型如下"><a href="#常见CRC参数模型如下" class="headerlink" title="常见CRC参数模型如下:"></a>常见CRC参数模型如下:</h3><p>有些博客中提到多项式，例如CRC32，多项式为04C11DB7或EDB88320，其实，常用的标准CRC32的多项式应该是04C11DB7，这个标准的CRC32算法中输入值需要进行反转，而反转后的结果为EDB88320。因此，如果你是用的是04C11DB7作为多项式进行运算CRC32则需要进行反转操作，如果使用多项式EDB88320进行运算则不需要进行反转，否则将会出现结果和其他工具得到的结果不同的情况。以下是通过博客找到的一部分CRC算法的规则，在参考资料中有博客链接，这里摘抄一份备份一下。</p><table><thead><tr><th>CRC算法名称</th><th>多项式公式</th><th>宽度</th><th>多项式</th><th>初始值</th><th>结果异或值</th><th>输入值反转</th><th>输出值反转</th></tr></thead><tbody><tr><td>CRC-4/ITU</td><td>x4 + x + 1</td><td>4</td><td>03</td><td>00</td><td>00</td><td>true</td><td>true</td></tr><tr><td>CRC-5/EPC</td><td>x4 + x3 + 1</td><td>5</td><td>09</td><td>09</td><td>00</td><td>false</td><td>false</td></tr><tr><td>CRC-5/ITU</td><td>x5 + x4 + x2 + 1</td><td>5</td><td>15</td><td>00</td><td>00</td><td>true</td><td>true</td></tr><tr><td>CRC-5/USB</td><td>x5 + x2 + 1</td><td>5</td><td>05</td><td>1F</td><td>1F</td><td>true</td><td>true</td></tr><tr><td>CRC-6/ITU</td><td>x6 + x + 1</td><td>6</td><td>03</td><td>00</td><td>00</td><td>true</td><td>true</td></tr><tr><td>CRC-7/MMC</td><td>x7 + x3 + 1</td><td>7</td><td>09</td><td>00</td><td>00</td><td>false</td><td>false</td></tr><tr><td>CRC-8</td><td>x8 + x2 + x + 1</td><td>8</td><td>07</td><td>00</td><td>00</td><td>false</td><td>false</td></tr><tr><td>CRC-8/ITU</td><td>x8 + x2 + x + 1</td><td>8</td><td>07</td><td>00</td><td>55</td><td>false</td><td>false</td></tr><tr><td>CRC-8/ROHC</td><td>x8 + x2 + x + 1</td><td>8</td><td>07</td><td>FF</td><td>00</td><td>true</td><td>true</td></tr><tr><td>CRC-8/MAXIM</td><td>x8 + x5 + x4 + 1</td><td>8</td><td>31</td><td>00</td><td>00</td><td>true</td><td>true</td></tr><tr><td>CRC-16/IBM</td><td>x6 + x5 + x2 + 1</td><td>16</td><td>8005</td><td>0000</td><td>0000</td><td>true</td><td>true</td></tr><tr><td>CRC-16/MAXIM</td><td>x6 + x5 + x2 + 1</td><td>16</td><td>8005</td><td>0000</td><td>FFFF</td><td>true</td><td>true</td></tr><tr><td>CRC-16/USB</td><td>x6 + x5 + x2 + 1</td><td>16</td><td>8005</td><td>FFFF</td><td>FFFF</td><td>true</td><td>true</td></tr><tr><td>CRC-16/MODBUS</td><td>x6 + x5 + x2 + 1</td><td>16</td><td>8005</td><td>FFFF</td><td>0000</td><td>true</td><td>true</td></tr><tr><td>CRC-16/CCITT</td><td>x6 + x2 + x5 + 1</td><td>16</td><td>1021</td><td>0000</td><td>0000</td><td>true</td><td>true</td></tr><tr><td>CRC-16/CCITT-FALSE</td><td>x6 + x2 + x5 + 1</td><td>16</td><td>1021</td><td>FFFF</td><td>0000</td><td>false</td><td>false</td></tr><tr><td>CRC-16/x5</td><td>x6 + x2 + x5 + 1</td><td>16</td><td>1021</td><td>FFFF</td><td>FFFF</td><td>true</td><td>true</td></tr><tr><td>CRC-16/XMODEM</td><td>x6 + x2 + x5 + 1</td><td>16</td><td>1021</td><td>0000</td><td>0000</td><td>false</td><td>false</td></tr><tr><td>CRC-16/DNP</td><td>x6 + x3 + x2 + x1 + x0 + x8 + x6 + x5 + x2 + 1</td><td>16</td><td>3D65</td><td>0000</td><td>FFFF</td><td>true</td><td>true</td></tr><tr><td>CRC-32</td><td>x2 + x6 + x3 + x2 + x6 + x2 + x1 + x0 + x8 + x7 + x5 + x4 + x2 + x + 1</td><td>32</td><td>04C11DB7</td><td>FFFFFFFF</td><td>FFFFFFFF</td><td>true</td><td>true</td></tr><tr><td>CRC-32/MPEG-2</td><td>x32 + x6 + x3 + x2 + x6 + x2 + x1 + x0 + x8 + x7 + x5 + x4 + x2 + x + 1</td><td>32</td><td>04C11DB7</td><td>FFFFFFFF</td><td>00000000</td><td>false</td><td>false</td></tr></tbody></table><h3 id="JAVA实现CRC32检验算法"><a href="#JAVA实现CRC32检验算法" class="headerlink" title="JAVA实现CRC32检验算法"></a>JAVA实现CRC32检验算法</h3><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><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></pre></td><td class="code"><pre><span class="line">public class CRC &#123;</span><br><span class="line"></span><br><span class="line">    private static long[] tables = new long[256];</span><br><span class="line"></span><br><span class="line">    /**</span><br><span class="line">     * 初始化CRC字符表</span><br><span class="line">     * @param poly 多项式</span><br><span class="line">     * @param polySize 多项式长度</span><br><span class="line">     * @param revese 是否翻转处理</span><br><span class="line">     */</span><br><span class="line">    public void initTable(long poly, int polySize, boolean revese) &#123;</span><br><span class="line">        if (revese) &#123;</span><br><span class="line">            poly = reversePoly(poly, polySize);</span><br><span class="line">        &#125;</span><br><span class="line">        long charValue;</span><br><span class="line">        for (int i = 0, length = tables.length; i &lt; length; i++) &#123;</span><br><span class="line">            charValue = i;</span><br><span class="line">            //由于ascii为8bit的字符，因此这里的maxLength为8。</span><br><span class="line">            for (int j = 0; j &lt; 8; j++) &#123;</span><br><span class="line">                if ((charValue &amp; 0x01) == 1) &#123;</span><br><span class="line">                    charValue = (charValue &gt;&gt; 1) ^ poly;</span><br><span class="line">                &#125; else &#123;</span><br><span class="line">                    charValue = charValue &gt;&gt; 1;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">            tables[i] = charValue;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    /**</span><br><span class="line">     * 按位翻转</span><br><span class="line">     * @param poly 多项式</span><br><span class="line">     * @param bitLength 翻转长度</span><br><span class="line">     * @return 翻转多项式结果</span><br><span class="line">     */</span><br><span class="line">    private long reversePoly(long poly, int bitLength) &#123;</span><br><span class="line">        long reversePoly = 0;</span><br><span class="line">        for (int i = 0; i &lt; bitLength; i++) &#123;</span><br><span class="line">            reversePoly &lt;&lt;= 1;</span><br><span class="line">            reversePoly |= (poly &amp; 0x01);</span><br><span class="line">            poly &gt;&gt;&gt;= 1;</span><br><span class="line">        &#125;</span><br><span class="line">        return reversePoly;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    /**</span><br><span class="line">     * 获取整型CRC检验码</span><br><span class="line">     * @param data 数据源</span><br><span class="line">     * @return 整型CRC检验码</span><br><span class="line">     */</span><br><span class="line">    private int getCRCValue(byte[] data) &#123;</span><br><span class="line">        //因为crcValue要做位运算，因此这里应该使用长整型避免负数造成计算结果错误</span><br><span class="line">        long crcValue = 0xFFFFFFFFL;</span><br><span class="line">        int length = data.length;</span><br><span class="line">        for (int i = 0; i &lt; length; i++) &#123;</span><br><span class="line">            int crcIndex = (int) (crcValue ^ data[i]) &amp; 0xFF;</span><br><span class="line">            crcValue = (crcValue &gt;&gt; 8) ^ tables[crcIndex];</span><br><span class="line">        &#125;</span><br><span class="line">        return (int) (crcValue ^ 0XFFFFFFFFL);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    /**</span><br><span class="line">     * 获取十六进制CRC检验码</span><br><span class="line">     * @param data 数据源</span><br><span class="line">     * @return 十六进制CRC检验码</span><br><span class="line">     */</span><br><span class="line">    public String getCRC(byte[] data) &#123;</span><br><span class="line">        long crcValue = getCRCValue(data) | 0x0000000100000000L;</span><br><span class="line">        String crcHex = Long.toHexString(crcValue);</span><br><span class="line">        int crcHexLength = crcHex.length();</span><br><span class="line">        return crcHex.substring(crcHexLength - 8, crcHexLength).toUpperCase();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    public static void main(String[] args) &#123;</span><br><span class="line">        </span><br><span class="line">        //CRC校验码测试用例</span><br><span class="line">        &#123;</span><br><span class="line">            CRC crc = new CRC();</span><br><span class="line">            crc.initTable(0x04C11DB7L, 32, true);</span><br><span class="line">            //需要输入长整型，避免有符号位运算影响</span><br><span class="line">            // crc.initTable(0xEDB88320L, false);</span><br><span class="line">            String crcResult = null;</span><br><span class="line">            byte[] data = &#123; (byte) 0x31, (byte) 0x32, (byte) 0x33, (byte) 0x34, (byte) 0x35, (byte) 0x36, (byte) 0x37,</span><br><span class="line">                    (byte) 0x38, (byte) 0x39, (byte) 0x30 &#125;;</span><br><span class="line">            crcResult = crc.getCRC(data);</span><br><span class="line">            System.out.println(crcResult);</span><br><span class="line"></span><br><span class="line">            //翻转检验</span><br><span class="line">            &#123;</span><br><span class="line">                System.out.println(Long.toBinaryString(0XFFFFFFFFFFFFFFF0L));</span><br><span class="line">                System.out.println(Long.toBinaryString(crc.reversePoly(0XFFFFFFFFFFFFFFF0L, 64)));</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        //CRC字符表输出</span><br><span class="line">        &#123;</span><br><span class="line">            StringBuffer sb = new StringBuffer();</span><br><span class="line">            sb.append(&quot;&#123;&quot;);</span><br><span class="line">            for (int i = 0, length = tables.length; i &lt; length; i++) &#123;</span><br><span class="line">                long crcValue = tables[i] | 0x0000000100000000L;</span><br><span class="line">                String hexValue = Long.toHexString(crcValue);</span><br><span class="line">                int hexValueLength = hexValue.length();</span><br><span class="line">                hexValue = hexValue.substring(hexValueLength - 8, hexValueLength);</span><br><span class="line">                sb.append(&quot;0x&quot;);</span><br><span class="line">                sb.append(hexValue.toUpperCase());</span><br><span class="line">                sb.append(&quot;,&quot;);</span><br><span class="line">            &#125;</span><br><span class="line">            sb.deleteCharAt(sb.length() - 1);</span><br><span class="line">            sb.append(&quot;&#125;&quot;);</span><br><span class="line">            System.out.println(sb);</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><h3 id="后记"><a href="#后记" class="headerlink" title="后记"></a>后记</h3><p>感觉各种技术都有人在之前写好了，而且写的都很好，而我一上手写这篇博客的时候发现完全没有下手的空间，没有任何创新点，也不能把CRC算法解释得更简单。因此，这里也就只能作为一次学习笔记来看了。很久没更新技术类博客了，但愿自己以后能够积极更新。</p>]]></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;这段时间处于待业状态中，所以就自己捣鼓些东西，学习学习有趣的算法。因为对于文件的校验可以通过CRC、SHA和MD5等方式进行，所以有了一个想</summary>
      
    
    
    
    <category term="dev" scheme="https://www.klavor.com/categories/dev/"/>
    
    
    <category term="Java" scheme="https://www.klavor.com/tags/Java/"/>
    
    <category term="CRC" scheme="https://www.klavor.com/tags/CRC/"/>
    
    <category term="算法原理" scheme="https://www.klavor.com/tags/%E7%AE%97%E6%B3%95%E5%8E%9F%E7%90%86/"/>
    
    <category term="多项式" scheme="https://www.klavor.com/tags/%E5%A4%9A%E9%A1%B9%E5%BC%8F/"/>
    
  </entry>
  
  <entry>
    <title>理幻</title>
    <link href="https://www.klavor.com/essay/20190511-541.html"/>
    <id>https://www.klavor.com/essay/20190511-541.html</id>
    <published>2019-05-10T16:00:00.000Z</published>
    <updated>2025-11-01T00:45:46.348Z</updated>
    
    <content type="html"><![CDATA[<p>今天突然兴致大好，想写很多很多的东西，于是乎想到了理幻这么一个词。理幻，我已经用了很久的一个网名，如果是放到写作中的话应该可以算是笔名了吧，如果没记错的话也许小学就开始了，又或者初中，总之是觉得陪伴已久。<br>关于理幻这一名字的出处，那是我在老爸的书里看到的一个名称后想到的，小时候翻着书柜里的书看，有一些是很早年的书了，标价才分毛的那种。一天，翻到了一本数学兴趣类的书，翻过封面，就可以看到一个“理巧想”的名称，仔细一想，就知道是老爸名字的谐音，想着觉得挺有意思的，所以也琢磨着给自己去一个类似的名称，那么“理”字就不必考虑了，至于“欢”字要用什么字代替比较好，“环”、“焕”、“桓”还是“幻”呢？总之想了同音的几个比较好看的词之后，觉得“幻”这个字更好一些，配合上“理”字，理性的幻想，还是挺有含义的，因此，也就有了理幻这么一个词。<br>至于，为什么要写这么一篇文章，那是因为要混搜索引擎收录，因为在早些年，我所有的网名都是用的理幻这个名字，所以只要在搜索引擎输入理幻就准能搜索到，并且还是排在了第一的位置，近几年由于自己停更了，而且因为一些个人原因准备舍弃理幻这个名字重新开始，于是把常用的几个网站的名称都改了，现在再搜索理幻这个词已经不再能轻易搜索到了，而这一篇文章则是为了让这个名称继续保持着，因为虽然不使用了，但是还是很有意义的一个名字。<br>目前，已经完全使用klavor这个名称代替了理幻，klavor中文我将其翻译为了克莱福尔，词源自于clever变形，灵感来自于可爱美丽的学姐silly，而恰巧，klavor一词的域名还没有被注册，因此最终被选用了。<br>理幻，陪伴了我多年的名称，将会一直被记载于网络之中。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;今天突然兴致大好，想写很多很多的东西，于是乎想到了理幻这么一个词。理幻，我已经用了很久的一个网名，如果是放到写作中的话应该可以算是笔名了吧，如果没记错的话也许小学就开始了，又或者初中，总之是觉得陪伴已久。&lt;br&gt;关于理幻这一名字的出处，那是我在老爸的书里看到的一个名称后想到</summary>
      
    
    
    
    <category term="essay" scheme="https://www.klavor.com/categories/essay/"/>
    
    
    <category term="理幻" scheme="https://www.klavor.com/tags/%E7%90%86%E5%B9%BB/"/>
    
  </entry>
  
  <entry>
    <title>「JS教程」仿照CSDN的copyright.js实现复制文本自动添加版权声明功能</title>
    <link href="https://www.klavor.com/dev/20190308-367.html"/>
    <id>https://www.klavor.com/dev/20190308-367.html</id>
    <published>2019-03-07T16:00:00.000Z</published>
    <updated>2025-11-01T00:45:46.341Z</updated>
    
    <content type="html"><![CDATA[<p>CSDN网站里有这样一个功能：复制文本的时候有时候会额外复制出一些页面的版权信息，有时候又不会出现这种情况，很好奇是怎么实现的。于是便从页面的代码下手去找实现代码。</p><p>先是打开了随便一篇CSDN的博客，通过右键的查看源码选项来查看页面代码。如图所示：</p><p><img src="https://img.klavor.com/2019/03/csdn-copyright-source-code-01.png" alt="仿照CSDN的copyright.js实现复制文本自动添加版权声明功能"></p><p>在源码页面按“Ctrl+F”，并搜索“.js”，然后逐个的浏览了这些文件的源码，终于发现了一个名叫copyright.js的文件，而里面的代码正是实现了用户复制文本时自动添加额外信息的功能逻辑。</p><p><img src="https://img.klavor.com/2019/03/csdn-copyright-source-code-02.png" alt="仿照CSDN的copyright.js实现复制文本自动添加版权声明功能"></p><p><strong>copyright.js源码：</strong></p><figure class="highlight javascript"><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></pre></td><td class="code"><pre><span class="line">!</span><br><span class="line"><span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="keyword">var</span> i = <span class="literal">null</span>;</span><br><span class="line">    <span class="function"><span class="keyword">function</span> <span class="title">t</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">        <span class="built_in">this</span>.textData = <span class="literal">null</span>,</span><br><span class="line">        <span class="built_in">this</span>.htmlData = <span class="literal">null</span>,</span><br><span class="line">        i = <span class="built_in">this</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">function</span> <span class="title">d</span>(<span class="params">t</span>) </span>&#123;</span><br><span class="line">        &lt;!-- 判断选中文本的长度 --&gt;</span><br><span class="line">        <span class="keyword">if</span> (<span class="number">140</span> &lt; <span class="built_in">window</span>.getSelection().getRangeAt(<span class="number">0</span>).toString().length) &#123;</span><br><span class="line">            <span class="keyword">var</span> e;</span><br><span class="line">            t.preventDefault(),</span><br><span class="line">            &lt;!-- 如果长度满足拼接上版权信息 --&gt;</span><br><span class="line">            e = <span class="built_in">window</span>.getSelection() + i.textData;</span><br><span class="line">            <span class="built_in">window</span>.getSelection(),</span><br><span class="line">            i.htmlData;</span><br><span class="line">            &lt;!-- 各种处理文本复制 --&gt;</span><br><span class="line">            <span class="keyword">if</span> (t.clipboardData) t.clipboardData.setData(<span class="string">&quot;text/plain&quot;</span>, e);</span><br><span class="line">            <span class="keyword">else</span> &#123;</span><br><span class="line">                <span class="keyword">if</span> (<span class="built_in">window</span>.clipboardData) <span class="keyword">return</span> <span class="built_in">window</span>.clipboardData.setData(<span class="string">&quot;text&quot;</span>, e);</span><br><span class="line">                n = e,</span><br><span class="line">                (a = <span class="built_in">document</span>.createElement(<span class="string">&quot;textarea&quot;</span>)).style.cssText = <span class="string">&quot;position: fixed;z-index: -10;top: -50px;left: -50px;&quot;</span>,</span><br><span class="line">                a.innerHTML = n,</span><br><span class="line">                <span class="built_in">document</span>.getElementsByTagName(<span class="string">&quot;body&quot;</span>)[<span class="number">0</span>].appendChild(a),</span><br><span class="line">                a.select(),</span><br><span class="line">                <span class="built_in">document</span>.execCommand(<span class="string">&quot;copy&quot;</span>)</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">var</span> n, a</span><br><span class="line">    &#125;</span><br><span class="line">    t.prototype.init = <span class="function"><span class="keyword">function</span>(<span class="params">t, e, n</span>) </span>&#123;</span><br><span class="line">        <span class="keyword">var</span> a, i, o;</span><br><span class="line">        <span class="built_in">this</span>.textData = e,</span><br><span class="line">        <span class="built_in">this</span>.htmlData = n,</span><br><span class="line">        i = <span class="string">&quot;copy&quot;</span>,</span><br><span class="line">        o = d,</span><br><span class="line">        &lt;!-- 监听copy事件 --&gt;</span><br><span class="line">        &lt;!-- 如果a的addEventListener和attachEvent都未定义则设置oncopy的事件回调 --&gt;</span><br><span class="line">        (a = t).addEventListener ? a.addEventListener(i, o, !<span class="number">1</span>) : a.attachEvent ? a.attachEvent(<span class="string">&quot;on&quot;</span> + i, o) : a[<span class="string">&quot;on&quot;</span> + i] = o</span><br><span class="line">    &#125;,</span><br><span class="line">    <span class="built_in">window</span>.csdn = <span class="built_in">window</span>.csdn ? <span class="built_in">window</span>.csdn: &#123;&#125;,</span><br><span class="line">    csdn.copyright = <span class="keyword">new</span> t</span><br><span class="line">&#125; ();</span><br></pre></td></tr></table></figure><p>虽然对javascript不熟悉，但是这些代码还是能勉强看懂的。只是有两个地方比较不太理解，一个是t.preventDefault()是做什么用的，后来问了一个做前端的朋友，说是什么阻止冒泡，嗯不太理解定义；另外一个是添加了textarea的标签并实现复制之后为什么不删除这个标签？也许是其他地方做了删除的动作了吗？</p><p>于是，根据CSDN的这段代码再加上前端小伙伴的指导，简单的实现了自己的网站的版权代码。</p><figure class="highlight javascript"><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">&lt;script type=<span class="string">&quot;text/javascript&quot;</span>&gt;</span><br><span class="line"><span class="built_in">document</span>.body.addEventListener(<span class="string">&#x27;copy&#x27;</span>, <span class="function"><span class="keyword">function</span>(<span class="params">t</span>) </span>&#123;</span><br><span class="line"><span class="keyword">if</span> (<span class="number">140</span> &lt; <span class="built_in">window</span>.getSelection().getRangeAt(<span class="number">0</span>).toString().length) &#123;</span><br><span class="line"><span class="keyword">var</span> n;</span><br><span class="line">t.preventDefault(),</span><br><span class="line">n = <span class="built_in">window</span>.getSelection();</span><br><span class="line">&lt;?php</span><br><span class="line"><span class="built_in">global</span> $wp;</span><br><span class="line">$current_url = home_url(add_query_arg(array(),$wp-&gt;request));</span><br><span class="line">$content = <span class="string">&#x27;\r\n---------------------&#x27;</span>;</span><br><span class="line">$content .= <span class="string">&#x27;\r\n作者：&#x27;</span>.get_the_author();</span><br><span class="line">$content .= <span class="string">&#x27;\r\n来源：&#x27;</span>.mb_convert_encoding(get_bloginfo(<span class="string">&#x27;name&#x27;</span>), <span class="string">&quot;UTF-8&quot;</span>, <span class="string">&quot;HTML-ENTITIES&quot;</span>);</span><br><span class="line">$content .= <span class="string">&#x27;\r\n原文：&#x27;</span>.$current_url;</span><br><span class="line">$content .= <span class="string">&#x27;\r\n版权声明：本文为博主原创文章，转载请附上博文链接！&#x27;</span>;</span><br><span class="line">echo <span class="string">&#x27;n = n + &quot;&#x27;</span>.$content.<span class="string">&#x27;&quot;;&#x27;</span>;</span><br><span class="line">?&gt;</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (t.clipboardData) t.clipboardData.setData(<span class="string">&quot;text/plain&quot;</span>, n);</span><br><span class="line"><span class="keyword">else</span> &#123;</span><br><span class="line"><span class="keyword">if</span> (<span class="built_in">window</span>.clipboardData) <span class="keyword">return</span> <span class="built_in">window</span>.clipboardData.setData(<span class="string">&quot;text&quot;</span>, n);</span><br><span class="line">(a = <span class="built_in">document</span>.createElement(<span class="string">&quot;textarea&quot;</span>)).style.cssText = <span class="string">&quot;position: fixed;z-index: -10;top: -50px;left: -50px;&quot;</span>,</span><br><span class="line">a.id = <span class="string">&#x27;copyright&#x27;</span>,</span><br><span class="line">a.innerHTML = n,</span><br><span class="line"><span class="built_in">document</span>.getElementsByTagName(<span class="string">&quot;body&quot;</span>)[<span class="number">0</span>].appendChild(a),</span><br><span class="line">a.select(),</span><br><span class="line"><span class="built_in">document</span>.execCommand(<span class="string">&quot;copy&quot;</span>);</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line">&#125;)</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure><p>经过不完全测试，还勉强能用，其中一个t.preventDefault()如果不调用的话就会出现递归问题等甚多奇葩的情况而不能实现功能，具体还得先了解一下概念了。</p><p>当然啦，还有一点要说的是，还需要添加一个“cut”的事件监听，鼠标右键的选项里没有剪切的选项，但是如果直接按组合键“Ctrl+X”的话还是能复制文本而没有加入版权声明的文本。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;CSDN网站里有这样一个功能：复制文本的时候有时候会额外复制出一些页面的版权信息，有时候又不会出现这种情况，很好奇是怎么实现的。于是便从页面的代码下手去找实现代码。&lt;/p&gt;
&lt;p&gt;先是打开了随便一篇CSDN的博客，通过右键的查看源码选项来查看页面代码。如图所示：&lt;/p&gt;
&lt;</summary>
      
    
    
    
    <category term="dev" scheme="https://www.klavor.com/categories/dev/"/>
    
    
    <category term="Javascript" scheme="https://www.klavor.com/tags/Javascript/"/>
    
    <category term="JS教程" scheme="https://www.klavor.com/tags/JS%E6%95%99%E7%A8%8B/"/>
    
    <category term="CSDN，copyright" scheme="https://www.klavor.com/tags/CSDN%EF%BC%8Ccopyright/"/>
    
    <category term="版权声明" scheme="https://www.klavor.com/tags/%E7%89%88%E6%9D%83%E5%A3%B0%E6%98%8E/"/>
    
  </entry>
  
  <entry>
    <title>「解决方案」Gradle’s dependency cache may be corrupt (this sometimes occurs after a network connection timeout.)</title>
    <link href="https://www.klavor.com/dev/20190307-344.html"/>
    <id>https://www.klavor.com/dev/20190307-344.html</id>
    <published>2019-03-06T16:00:00.000Z</published>
    <updated>2025-11-01T00:45:46.336Z</updated>
    
    <content type="html"><![CDATA[<p>在打开一个别人项目的时候，由于每个人使用的Android Studio的版本都不一样，因此可能会从服务器去下载对应Gragle的版本，而这个时候常常会出现各种异常情况。如同本篇文章中所要讲述的下载Gradle版本失败的情况。在Android Studio中提示了Failed to open zip file.Gradle’s dependency cache may be corrupt (this sometimes occurs after a network connection timeout.)。具体的错误日志如下：</p><figure class="highlight gradle"><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">Download https:<span class="comment">//services.gradle.org/distributions/gradle-4.4-all.zip (94.25 MB)</span></span><br><span class="line">[ <span class="number">75</span>%] [ =========================================&gt;             ] <span class="number">71.01</span> MB</span><br><span class="line">Download https:<span class="comment">//services.gradle.org/distributions/gradle-4.4-all.zip succeeded, took 20 m 33 s 787 ms</span></span><br><span class="line">Unzipping ...</span><br><span class="line"></span><br><span class="line">Failed to open zip <span class="keyword">file</span>.</span><br><span class="line">Gradle<span class="string">&#x27;s dependency cache may be corrupt (this sometimes occurs after a network connection timeout.)</span></span><br><span class="line"><span class="string">Re-download dependencies and sync project (requires network)</span></span><br><span class="line"><span class="string">Re-download dependencies and sync project (requires network)</span></span><br></pre></td></tr></table></figure><p>从错误日志中可以看出,这是由于网络不稳定导致了下载中断，下载的Gradle版本包不完整而导致了无法解压文件。这时如果点击“Re-download dependencies and sync project (requires network)”进行重新尝试的话也并不能解决问题，又会出现如下提示：</p><figure class="highlight gradle"><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">Failed to open zip <span class="keyword">file</span>.</span><br><span class="line">Gradle<span class="string">&#x27;s dependency cache may be corrupt (this sometimes occurs after a network connection timeout.)</span></span><br><span class="line"><span class="string">Re-download dependencies and sync project (requires network)</span></span><br><span class="line"><span class="string">Re-download dependencies and sync project (requires network)</span></span><br></pre></td></tr></table></figure><p>原因应该是在路径下面已经存在了下载的Gradle包而运行的时候却无法解压导致的，需要手动的将不完整的Gradle包删除后再重新的尝试。</p><p><img src="https://img.klavor.com/2019/03/gradles-dependency-cache-may-be-corrupt-02.png" alt="Gradle&#39;s dependency cache may be corrupt (this sometimes occurs after a network connection timeout.)"></p><p>根据每个人电脑的不同，定位到.gradle的文件夹下面。随后可以参考以下路径进行删除不完整的Gradle版本包。</p><figure class="highlight gradle"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">C:\Users\KLAVOR\.gradle\wrapper\dists\gradle-<span class="number">4.4</span>-all\<span class="number">9</span>br9xq1tocpiv8o6njlyu5op1</span><br></pre></td></tr></table></figure><p>如下图所示，文件夹下包含了一个“gradle-4.4-all.zip”文件和一个“gradle-4.4-all.zip.lck”文件，然后如果将这两个文件删除后并点击Android Studio错误日志栏里面的“Re-download dependencies and sync project (requires network)”后，Android Studio将会重新下载这个版本的Gradle包。但是，由于网络原因可能还是会失败。</p><p><img src="https://img.klavor.com/2019/03/gradles-dependency-cache-may-be-corrupt-01.png" alt="Gradle&#39;s dependency cache may be corrupt (this sometimes occurs after a network connection timeout.)"></p><p>这个时候有两种方式解决这个问题。</p><p><strong>方法一：</strong></p><p>将项目中gradle目录下的子目录wrapper中的gradle-wrapper.properties文件从</p><figure class="highlight gradle"><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">#Mon Mar <span class="number">04</span> <span class="number">10</span>:<span class="number">16</span>:<span class="number">37</span> CST <span class="number">2019</span></span><br><span class="line">distributionBase=GRADLE_USER_HOME</span><br><span class="line">distributionPath=wrapper/dists</span><br><span class="line">zipStoreBase=GRADLE_USER_HOME</span><br><span class="line">zipStorePath=wrapper/dists</span><br><span class="line">distributionUrl=https\:<span class="comment">//services.gradle.org/distributions/gradle-4.4-all.zip</span></span><br></pre></td></tr></table></figure><p>改为</p><figure class="highlight gradle"><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">#Mon Mar <span class="number">04</span> <span class="number">10</span>:<span class="number">16</span>:<span class="number">37</span> CST <span class="number">2019</span></span><br><span class="line">distributionBase=GRADLE_USER_HOME</span><br><span class="line">distributionPath=wrapper/dists</span><br><span class="line">zipStoreBase=GRADLE_USER_HOME</span><br><span class="line">zipStorePath=wrapper/dists</span><br><span class="line">distributionUrl=http\:<span class="comment">//services.gradle.org/distributions/gradle-4.4-all.zip</span></span><br></pre></td></tr></table></figure><p>就是将https改成了http，然后同步一下gradle就可以了。</p><p><strong>方法二：</strong></p><p>和方法一类似，将失败的链接从<code>https://services.gradle.org/distributions/gradle-4.4-all.zip</code>改为<code>http://services.gradle.org/distributions/gradle-4.4-all.zip</code>后到浏览器地址栏里粘贴上去将这个文件下载下来。为什么要将https改成http呢？原因虽然不太清楚，但是改成http之后下载速度就变得极快了，个人猜测是https和http协议部署的服务器不一样又或者https校验根证书的时候证书提供商的地址被墙或者其他什么原因吧。</p><p>下载完成之后将“gradle-4.4-all.zip”文件复制到“C:\Users\KLAVOR.gradle\wrapper\dists\gradle-4.4-all\9br9xq1tocpiv8o6njlyu5op1”（.gradle文件夹的路径根据个人电脑而定），并对zip压缩包进行解压，随后复制“gradle-4.4-all.zip.lck”文件（创建一个空白的新文件也可以）并将文件命名为“gradle-4.4-all.zip.ok”。如下图所示：</p><p><img src="https://img.klavor.com/2019/03/gradles-dependency-cache-may-be-corrupt-03.png" alt="Gradle&#39;s dependency cache may be corrupt (this sometimes occurs after a network connection timeout.)"></p><p>这时候就大功告成了，重新点击“Re-download dependencies and sync project (requires network)”就能够正常运行了。</p><p><img src="https://img.klavor.com/2019/03/gradles-dependency-cache-may-be-corrupt-04.png" alt="Gradle&#39;s dependency cache may be corrupt (this sometimes occurs after a network connection timeout.)"></p><p>对于这类问题，博主不止一次遇到了，在这里记录一下并分享给遇到同样问题的开发者们。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;在打开一个别人项目的时候，由于每个人使用的Android Studio的版本都不一样，因此可能会从服务器去下载对应Gragle的版本，而这个时候常常会出现各种异常情况。如同本篇文章中所要讲述的下载Gradle版本失败的情况。在Android Studio中提示了Failed</summary>
      
    
    
    
    <category term="dev" scheme="https://www.klavor.com/categories/dev/"/>
    
    
    <category term="Android" scheme="https://www.klavor.com/tags/Android/"/>
    
    <category term="解决方案" scheme="https://www.klavor.com/tags/%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88/"/>
    
    <category term="Gradle" scheme="https://www.klavor.com/tags/Gradle/"/>
    
    <category term="dependency" scheme="https://www.klavor.com/tags/dependency/"/>
    
    <category term="依赖包" scheme="https://www.klavor.com/tags/%E4%BE%9D%E8%B5%96%E5%8C%85/"/>
    
  </entry>
  
  <entry>
    <title>「探索发现」Java反汇编字节码指令分析String和StringBuffer字符串拼接的区别</title>
    <link href="https://www.klavor.com/dev/20190227-335.html"/>
    <id>https://www.klavor.com/dev/20190227-335.html</id>
    <published>2019-02-26T16:00:00.000Z</published>
    <updated>2025-11-01T00:45:46.336Z</updated>
    
    <content type="html"><![CDATA[<h3 id="问题导出"><a href="#问题导出" class="headerlink" title="问题导出"></a>问题导出</h3><p>最近一直在复习知识点。今天在网上看到了一篇关于代码优化的文章，文章里谈到了字符串拼接的优化,通过String替代StringBuffer将多行代码优化成1行代码。代码如下：</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">//StringBuffer拼接</span></span><br><span class="line">StringBuffer sb = <span class="keyword">new</span> StringBuffer();</span><br><span class="line">sb.append(<span class="string">&quot;abc&quot;</span>);</span><br><span class="line">sb.append(<span class="string">&quot;-&quot;</span>);</span><br><span class="line">sb.append(<span class="string">&quot;123&quot;</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">//String拼接</span></span><br><span class="line">String a = <span class="string">&quot;abc&quot;</span> + <span class="string">&quot;-&quot;</span> + <span class="string">&quot;123&quot;</span>;</span><br></pre></td></tr></table></figure><p>看到这心里满是疑惑，因为在这之前，一直认为字符串拼接的时候用StringBuffer效率会更高，而String拼接时会在内存中产生多个无用的对象，浪费内存和降低执行效率。于是抱着求知的心态，运用了Java反汇编的方式试着从字节码指令里看出什么门道来。</p><h3 id="简单DEMO"><a href="#简单DEMO" class="headerlink" title="简单DEMO"></a>简单DEMO</h3><p>首先，用java写一个简单的Demo。代码如下：</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Test</span> </span>&#123;</span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">string1();</span><br><span class="line">string2();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">string1</span><span class="params">()</span> </span>&#123;</span><br><span class="line">String a = <span class="string">&quot;abc&quot;</span> + <span class="string">&quot;-&quot;</span> + <span class="string">&quot;123&quot;</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">string2</span><span class="params">()</span> </span>&#123;</span><br><span class="line">StringBuffer sb = <span class="keyword">new</span> StringBuffer();</span><br><span class="line">sb.append(<span class="string">&quot;abc&quot;</span>);</span><br><span class="line">sb.append(t);</span><br><span class="line">sb.append(<span class="string">&quot;123&quot;</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">string3</span><span class="params">()</span> </span>&#123;</span><br><span class="line">String a = <span class="string">&quot;abc&quot;</span> + t + <span class="string">&quot;123&quot;</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">string4</span><span class="params">()</span> </span>&#123;</span><br><span class="line">String a = <span class="string">&quot;abc&quot;</span> + t;</span><br><span class="line">a = a + <span class="string">&quot;123&quot;</span>;</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> String t = <span class="string">&quot;-&quot;</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>其中：</p><ul><li>string1()方法，对3个字符串常量进行了直接拼接。</li><li>string2()方法，通过StringBuffer拼接的方式对2个字符串常量与1个静态字符串变量进行了拼接（之所以不是3个字符串常量而是2个字符串常量和1个静态字符串变量是为了与string3()进行对比）。</li><li>string3()方法，对2个字符串常量和1个静态字符串变量进行直接拼接。</li><li>string4()方法，对2个字符串常量和1个静态字符串变量进行分段拼接。</li></ul><h3 id="JAVA反汇编"><a href="#JAVA反汇编" class="headerlink" title="JAVA反汇编"></a>JAVA反汇编</h3><p>然后使用javac和javap命令对代码进行编译与反汇编。</p><p><img src="https://img.klavor.com/2019/03/string-and-stringbuffer-01.jpg" alt="Java反汇编字节码指令分析String和StringBuffer字符串拼接的区别"></p><h3 id="字节码指令分析"><a href="#字节码指令分析" class="headerlink" title="字节码指令分析"></a>字节码指令分析</h3><p>随后，得到了一个Test.txt文件，内容是反汇编后的java字节码指令。</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><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></pre></td><td class="code"><pre><span class="line">Compiled from &quot;Test.java&quot;</span><br><span class="line">public class Test &#123;</span><br><span class="line">  public Test();</span><br><span class="line">    Code:</span><br><span class="line">       0: aload_0</span><br><span class="line">       1: invokespecial #1                  // Method java/lang/Object.&quot;&lt;init&gt;&quot;:()V</span><br><span class="line">       4: return</span><br><span class="line"></span><br><span class="line">  public static void main(java.lang.String[]);</span><br><span class="line">    Code:</span><br><span class="line">       0: invokestatic  #2                  // Method string1:()V</span><br><span class="line">       3: invokestatic  #3                  // Method string2:()V</span><br><span class="line">       6: return</span><br><span class="line"></span><br><span class="line">  public static void string1();</span><br><span class="line">    Code:</span><br><span class="line">       0: ldc           #4                  // String abc-123</span><br><span class="line">       2: astore_0</span><br><span class="line">       3: return</span><br><span class="line"></span><br><span class="line">  public static void string2();</span><br><span class="line">    Code:</span><br><span class="line">       0: new           #5                  // class java/lang/StringBuffer</span><br><span class="line">       3: dup</span><br><span class="line">       4: invokespecial #6                  // Method java/lang/StringBuffer.&quot;&lt;init&gt;&quot;:()V</span><br><span class="line">       7: astore_0</span><br><span class="line">       8: aload_0</span><br><span class="line">       9: ldc           #7                  // String abc</span><br><span class="line">      11: invokevirtual #8                  // Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;</span><br><span class="line">      14: pop</span><br><span class="line">      15: aload_0</span><br><span class="line">      16: getstatic     #9                  // Field t:Ljava/lang/String;</span><br><span class="line">      19: invokevirtual #8                  // Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;</span><br><span class="line">      22: pop</span><br><span class="line">      23: aload_0</span><br><span class="line">      24: ldc           #10                 // String 123</span><br><span class="line">      26: invokevirtual #8                  // Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;</span><br><span class="line">      29: pop</span><br><span class="line">      30: return</span><br><span class="line"></span><br><span class="line">  public static void string3();</span><br><span class="line">    Code:</span><br><span class="line">       0: new           #11                 // class java/lang/StringBuilder</span><br><span class="line">       3: dup</span><br><span class="line">       4: invokespecial #12                 // Method java/lang/StringBuilder.&quot;&lt;init&gt;&quot;:()V</span><br><span class="line">       7: ldc           #7                  // String abc</span><br><span class="line">       9: invokevirtual #13                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;</span><br><span class="line">      12: getstatic     #9                  // Field t:Ljava/lang/String;</span><br><span class="line">      15: invokevirtual #13                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;</span><br><span class="line">      18: ldc           #10                 // String 123</span><br><span class="line">      20: invokevirtual #13                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;</span><br><span class="line">      23: invokevirtual #14                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;</span><br><span class="line">      26: astore_0</span><br><span class="line">      27: return</span><br><span class="line"></span><br><span class="line">  public static void string4();</span><br><span class="line">    Code:</span><br><span class="line">       0: new           #11                 // class java/lang/StringBuilder</span><br><span class="line">       3: dup</span><br><span class="line">       4: invokespecial #12                 // Method java/lang/StringBuilder.&quot;&lt;init&gt;&quot;:()V</span><br><span class="line">       7: ldc           #7                  // String abc</span><br><span class="line">       9: invokevirtual #13                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;</span><br><span class="line">      12: getstatic     #9                  // Field t:Ljava/lang/String;</span><br><span class="line">      15: invokevirtual #13                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;</span><br><span class="line">      18: invokevirtual #14                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;</span><br><span class="line">      21: astore_0</span><br><span class="line">      22: new           #11                 // class java/lang/StringBuilder</span><br><span class="line">      25: dup</span><br><span class="line">      26: invokespecial #12                 // Method java/lang/StringBuilder.&quot;&lt;init&gt;&quot;:()V</span><br><span class="line">      29: aload_0</span><br><span class="line">      30: invokevirtual #13                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;</span><br><span class="line">      33: ldc           #10                 // String 123</span><br><span class="line">      35: invokevirtual #13                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;</span><br><span class="line">      38: invokevirtual #14                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;</span><br><span class="line">      41: astore_0</span><br><span class="line">      42: return</span><br><span class="line"></span><br><span class="line">  static &#123;&#125;;</span><br><span class="line">    Code:</span><br><span class="line">       0: ldc           #15                 // String -</span><br><span class="line">       2: putstatic     #9                  // Field t:Ljava/lang/String;</span><br><span class="line">       5: return</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>通过以上的字节码指令可知：</p><ul><li>string1()方法中，在编译器编译的时候，由于是3个常量，所以编译器将代码优化成了一个拼接之后完整的字符串直接进行赋值；</li><li>string2()方法中，和先前了解到的情况一样，调用了3次append()方法进行拼接；</li><li>string3()方法中，编译器会创建一个StringBuffer对象然后再进行字符串拼接；</li><li>string4()方法中，因为是进行了分段拼接，编译器这时就会创建多个StringBuffer和调用多次toString()将StringBuffer转换成String。</li></ul><p>因此可知，正常情况下如果是在一行代码内进行字符串的拼接，可以不使用StringBuffer，因为编译器会在字符串拼接的时候自动创建StringBuffer来进行拼接。而如果是多段拼接，这个时候使用StringBuffer则会比String更节省内存和更加高效（因为String在多段拼接的时候会产生多个StringBuffer和String对象）。</p>]]></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;最近一直在复习知识点。今天在网上看到了一篇关于代码优化的文章，文章里谈到了字符串拼接的优化,通过String替代String</summary>
      
    
    
    
    <category term="dev" scheme="https://www.klavor.com/categories/dev/"/>
    
    
    <category term="Java" scheme="https://www.klavor.com/tags/Java/"/>
    
    <category term="探索发现" scheme="https://www.klavor.com/tags/%E6%8E%A2%E7%B4%A2%E5%8F%91%E7%8E%B0/"/>
    
    <category term="反汇编" scheme="https://www.klavor.com/tags/%E5%8F%8D%E6%B1%87%E7%BC%96/"/>
    
    <category term="字节码指令" scheme="https://www.klavor.com/tags/%E5%AD%97%E8%8A%82%E7%A0%81%E6%8C%87%E4%BB%A4/"/>
    
    <category term="String" scheme="https://www.klavor.com/tags/String/"/>
    
    <category term="StringBuffer" scheme="https://www.klavor.com/tags/StringBuffer/"/>
    
    <category term="字符串拼接" scheme="https://www.klavor.com/tags/%E5%AD%97%E7%AC%A6%E4%B8%B2%E6%8B%BC%E6%8E%A5/"/>
    
  </entry>
  
  <entry>
    <title>「WP教程」WordPress文章页面首尾添加自定义内容</title>
    <link href="https://www.klavor.com/dev/20190221-331.html"/>
    <id>https://www.klavor.com/dev/20190221-331.html</id>
    <published>2019-02-20T16:00:00.000Z</published>
    <updated>2025-11-01T00:45:46.336Z</updated>
    
    <content type="html"><![CDATA[<p>在使用wordpress建站的过程中，总会遇到一些需要定制的功能，如回复邮件提醒，指定位置插入内容，添加验证码，赞赏功能等等。今天添加赞赏功能的时候需要将赞赏的代码插入到文章的结尾处，于是Get了这么一个wordpress知识点，在此分享出来供大家参考以及自己备忘。而后又随便添加了版权声明的内容，不亦说乎。</p><h3 id="实现代码"><a href="#实现代码" class="headerlink" title="实现代码"></a>实现代码</h3><ul><li>添加内容到文章顶部</li></ul><figure class="highlight php"><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="function"><span class="keyword">function</span> <span class="title">add_article_copyright</span>(<span class="params"><span class="variable">$content</span></span>) </span>&#123;</span><br><span class="line">    <span class="keyword">if</span>(!is_feed() &amp;&amp; !is_home() &amp;&amp; is_singular() &amp;&amp; is_main_query()) &#123;</span><br><span class="line">        <span class="variable">$title</span> = get_the_title();</span><br><span class="line">        <span class="variable">$permalink</span> = get_permalink();</span><br><span class="line">        <span class="variable">$custom_header_content</span> = <span class="string">&#x27;&lt;p class=&quot;article-copyright&quot;&gt;原创文章如转载，请注明本文链接: &lt;a href=”&#x27;</span>.<span class="variable">$permalink</span>.<span class="string">&#x27;” title=”&#x27;</span>.<span class="variable">$title</span>.<span class="string">&#x27;”&gt;&#x27;</span>.<span class="variable">$permalink</span>.<span class="string">&#x27;&lt;/a&gt;&lt;/p&gt;&#x27;</span>;</span><br><span class="line">        <span class="variable">$content</span> = <span class="variable">$custom_header_content</span>.<span class="variable">$content</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> <span class="variable">$content</span>;</span><br><span class="line">&#125;</span><br><span class="line">add_filter(<span class="string">&#x27;the_content&#x27;</span>, <span class="string">&#x27;add_article_copyright&#x27;</span>);</span><br></pre></td></tr></table></figure><ul><li>添加内容到文章底部</li></ul><figure class="highlight php"><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="function"><span class="keyword">function</span> <span class="title">add_article_copyright</span>(<span class="params"><span class="variable">$content</span></span>) </span>&#123;</span><br><span class="line">    <span class="keyword">if</span>(!is_feed() &amp;&amp; !is_home() &amp;&amp; is_singular() &amp;&amp; is_main_query()) &#123;</span><br><span class="line">        <span class="variable">$title</span> = get_the_title();</span><br><span class="line">        <span class="variable">$permalink</span> = get_permalink();</span><br><span class="line">        <span class="variable">$custom_header_content</span> = <span class="string">&#x27;&lt;p class=&quot;article-copyright&quot;&gt;原创文章如转载，请注明本文链接: &lt;a href=”&#x27;</span>.<span class="variable">$permalink</span>.<span class="string">&#x27;” title=”&#x27;</span>.<span class="variable">$title</span>.<span class="string">&#x27;”&gt;&#x27;</span>.<span class="variable">$permalink</span>.<span class="string">&#x27;&lt;/a&gt;&lt;/p&gt;&#x27;</span>;</span><br><span class="line">        <span class="variable">$content</span> .= <span class="variable">$custom_header_content</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> <span class="variable">$content</span>;</span><br><span class="line">&#125;</span><br><span class="line">add_filter(<span class="string">&#x27;the_content&#x27;</span>, <span class="string">&#x27;add_article_copyright&#x27;</span>);</span><br></pre></td></tr></table></figure><h3 id="代码解析"><a href="#代码解析" class="headerlink" title="代码解析"></a>代码解析</h3><p>从上面的代码可以看出大致上是一样的，只是在拼接$content内容的时候先后顺序不一样。一个是将指定内容置于文章头部，另一个是将指定内容置于文章尾部。</p><figure class="highlight php"><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="comment">//将内容拼接到文章头部</span></span><br><span class="line"><span class="variable">$content</span> = <span class="variable">$custom_header_content</span>.<span class="variable">$content</span>;</span><br><span class="line"><span class="comment">//将内容拼接到文章尾部</span></span><br><span class="line"><span class="variable">$content</span> .= <span class="variable">$custom_header_content</span>;</span><br></pre></td></tr></table></figure><h3 id="注意事项"><a href="#注意事项" class="headerlink" title="注意事项"></a>注意事项</h3><p>在上述代码中用到了get_permalink()和get_the_title()两个函数，这两个函数是分别将文章链接和文章标题返回。还有与之很形似的两个函数the_permalink()和the_title()，这两个函数是分别打印文章链接和文章标题，而不是返回其内容。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;在使用wordpress建站的过程中，总会遇到一些需要定制的功能，如回复邮件提醒，指定位置插入内容，添加验证码，赞赏功能等等。今天添加赞赏功能的时候需要将赞赏的代码插入到文章的结尾处，于是Get了这么一个wordpress知识点，在此分享出来供大家参考以及自己备忘。而后又随</summary>
      
    
    
    
    <category term="dev" scheme="https://www.klavor.com/categories/dev/"/>
    
    
    <category term="Wordpress" scheme="https://www.klavor.com/tags/Wordpress/"/>
    
    <category term="自定义" scheme="https://www.klavor.com/tags/%E8%87%AA%E5%AE%9A%E4%B9%89/"/>
    
    <category term="WP教程" scheme="https://www.klavor.com/tags/WP%E6%95%99%E7%A8%8B/"/>
    
  </entry>
  
  <entry>
    <title>「WP教程」WordPress通过自定义字段控制指定页面功能的开关</title>
    <link href="https://www.klavor.com/dev/20190221-332.html"/>
    <id>https://www.klavor.com/dev/20190221-332.html</id>
    <published>2019-02-20T16:00:00.000Z</published>
    <updated>2025-11-01T00:45:46.336Z</updated>
    
    <content type="html"><![CDATA[<p>在使用wordpress的过程中，我遇到了这样一个问题：自定义一个插件，这个插件里做的事情是在文章尾部添加一个赞赏的功能，然而我希望能够控制在指定页面显示与隐藏这个赞赏功能。而这个时候，自定义字段就起到了很大的作用，可以通过每一篇文章中自定义字段的值来决定赞赏是开启还是关闭。</p><p>首先，当然是为文章或者页面新增一个自定义的字段。</p><p><img src="https://img.klavor.com/2019/03/how-to-create-custom-field-and-use-it-01.png" alt="开启自定义字段"><br>图1 开启自定义字段</p><p><img src="https://img.klavor.com/2019/03/how-to-create-custom-field-and-use-it-02.png" alt="新增自定义字段"><br>图2 新增自定义字段</p><p>随后，将可以在代码中获取到该字段的值。实现代码如下：</p><figure class="highlight php"><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="function"><span class="keyword">function</span> <span class="title">add_donate_qrcode</span>(<span class="params"><span class="variable">$content</span></span>) </span>&#123;</span><br><span class="line">  <span class="variable">$donate_qrcode</span> = get_post_meta(get_the_ID(), <span class="string">&#x27;donate_qrcode&#x27;</span>, <span class="literal">true</span>);</span><br><span class="line">  <span class="comment">//如果donate_qrcode为off则关闭赞赏功能</span></span><br><span class="line">  <span class="comment">//如果donate_qrcode没有定义则默认其为开启状态</span></span><br><span class="line">  <span class="keyword">if</span>(<span class="variable">$donate_qrcode</span> != <span class="string">&#x27;off&#x27;</span> &amp;&amp; !is_feed() &amp;&amp; !is_home() &amp;&amp; is_singular() &amp;&amp; is_main_query()) &#123;</span><br><span class="line">    <span class="variable">$content</span> .= <span class="string">&#x27;&lt;iframe style=&quot;overflow-x: hidden; overflow-y: hidden; border: 0xp none #fff; min-height: 240px;&quot; </span></span><br><span class="line"><span class="string">    src=&quot;https://www.klavor.com/donate/index.html&quot; frameborder=&quot;0&quot; scrolling=&quot;no&quot;&gt;&lt;/iframe&gt;&#x27;</span>;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> <span class="variable">$content</span>;</span><br><span class="line">&#125;</span><br><span class="line">add_filter(<span class="string">&#x27;the_content&#x27;</span>, <span class="string">&#x27;add_donate_qrcode&#x27;</span>);</span><br></pre></td></tr></table></figure><p>其中，get_post_meta()函数是这里的重点，通过这个函数可以获取到指定字段的值。这里通过donate_qrcode获取到文章或者页面中自定义字段的值，然后对这个值做判断来决定是开启还是关闭赞赏功能。</p><p>至此，一个根据自定义字段开关赞赏的功能就完成了，就这样又实现了一个功能。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;在使用wordpress的过程中，我遇到了这样一个问题：自定义一个插件，这个插件里做的事情是在文章尾部添加一个赞赏的功能，然而我希望能够控制在指定页面显示与隐藏这个赞赏功能。而这个时候，自定义字段就起到了很大的作用，可以通过每一篇文章中自定义字段的值来决定赞赏是开启还是关闭</summary>
      
    
    
    
    <category term="dev" scheme="https://www.klavor.com/categories/dev/"/>
    
    
    <category term="Wordpress" scheme="https://www.klavor.com/tags/Wordpress/"/>
    
    <category term="自定义" scheme="https://www.klavor.com/tags/%E8%87%AA%E5%AE%9A%E4%B9%89/"/>
    
    <category term="WP教程" scheme="https://www.klavor.com/tags/WP%E6%95%99%E7%A8%8B/"/>
    
  </entry>
  
  <entry>
    <title>「探索发现」通过反汇编Java字节码文件输出字节码指令探索有关i++的问题</title>
    <link href="https://www.klavor.com/dev/20190220-310.html"/>
    <id>https://www.klavor.com/dev/20190220-310.html</id>
    <published>2019-02-19T16:00:00.000Z</published>
    <updated>2025-11-01T00:45:46.336Z</updated>
    
    <content type="html"><![CDATA[<h3 id="问题引出"><a href="#问题引出" class="headerlink" title="问题引出"></a>问题引出</h3><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">int</span> i = <span class="number">0</span>;</span><br><span class="line">i = i++;</span><br><span class="line">最后i是多少？</span><br></pre></td></tr></table></figure><p>于是想了想便回答i = 1，但是没想到朋友说答案是i = 0。似乎有些出乎意料，印象里，i++是先将i的值赋值于指定变量后再做自增的。这里的代码不是应该是类似于</p><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">i=i;</span><br><span class="line">i=i+<span class="number">1</span>;</span><br></pre></td></tr></table></figure><p>如果是这样的话那i的值应该为1才是呀！疑惑不解！！！随后朋友便发来了几张程序运行图为他的答案做出了有力的支撑。</p><ul><li><strong>当i = i++时</strong></li></ul><p><img src="https://img.klavor.com/2019/03/javap-i-plus-plus-01.png" alt="当i = i++时"></p><ul><li><strong>当i = i++ + i++时</strong></li></ul><p><img src="https://img.klavor.com/2019/03/javap-i-plus-plus-02.png" alt="当i = i++ + i++时"></p><ul><li><strong>当i = i++ + i++ + i++时</strong></li></ul><p><img src="https://img.klavor.com/2019/03/javap-i-plus-plus-03.png" alt="当i = i++ + i++ + i++时"></p><p>看到了这些运行结果的截图，也不得不相信，但是心里还是充满了疑惑。</p><h3 id="寻根问底"><a href="#寻根问底" class="headerlink" title="寻根问底"></a>寻根问底</h3><p>对于这种现象，首先想到是不是i++与赋值操作是同时执行的？又或者，虚拟机在实现这类计算的时候是不是做了什么神奇的操作？怀抱着疑惑与求之的心态，开始了探索之旅。</p><ul><li><strong>i++与赋值操作是同时执行？</strong></li></ul><p>通过多次的运算后排除了这种可能性。</p><ul><li><strong>虚拟机是怎么实现这类运算的？</strong></li></ul><p>首先想到了Android上常见到的smali语言的虚拟机指令，所以百度了一下java相关的虚拟机指令的文章，看到了通过javap命令可以反汇编输出java虚拟机的字节码指令，于是考虑用这种方法进一步尝试。</p><h3 id="着手实验"><a href="#着手实验" class="headerlink" title="着手实验"></a>着手实验</h3><ul><li><strong>测试代码</strong></li></ul><p>首先写了一个简单的java测试代码，代码里面的main()方法就只有两行简单的语句。</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Test</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">int</span> i = <span class="number">0</span>;</span><br><span class="line">        i = i++;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ul><li><strong>反汇编java字节码文件</strong></li></ul><p>写好了demo之后，通过命令行窗口进行下一步操作。如图所示，通过javap命令输出反汇编后的文件内容，得到了java虚拟机的字节码指令。</p><p><img src="https://img.klavor.com/2019/03/javap-i-plus-plus-04.png" alt="反汇编java字节码文件"></p><ul><li><strong>理解指令处理流程</strong></li></ul><p>虽然以前有看过smali语法和一些简单的汇编语法，但是看到这个java的字节码指令后完全懵逼了。这些指令是什么意思都不知道，更别提阅读了。通过一番的搜索，查找到相关资料后，得到了一篇还比较全面的指令解释的文章。<br><strong><em><a href="https://www.cnblogs.com/tenghoo/p/jvm_opcodejvm.html">https://www.cnblogs.com/tenghoo/p/jvm_opcodejvm.html</a></em></strong>。<br>根据文章里的内容整理出了反汇编后出现的几个指令的意思。</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">iconst_n                将int型(n)推送至栈顶</span><br><span class="line">istore_n                将栈顶int型数值存入第n+1个本地变量</span><br><span class="line">iload_n                 将第n+1个int型本地变量推送至栈顶</span><br><span class="line">iinc n, m               局部变量自增指令,将第n+1个本地变量自增m</span><br></pre></td></tr></table></figure><p>顺着上面的这几条指令看，慢慢的揭开i=i++，最后i=0的神秘面纱了。</p><ul><li><strong>第一步指令：iconst_0</strong></li></ul><p>推送int型的数值0到栈顶中。</p><p><img src="https://img.klavor.com/2019/03/javap-i-plus-plus-05.png" alt="推送int型的数值0到栈顶中。"></p><ul><li><strong>第二步指令：istore_1</strong></li></ul><p>将栈顶int型数值存入到第2个本地变量</p><p><img src="https://img.klavor.com/2019/03/javap-i-plus-plus-06.png" alt="将栈顶int型数值存入到第2个本地变量"></p><ul><li><strong>第三步指令：iload_1</strong></li></ul><p>将第2个int型的本地变量推送至栈顶</p><p><img src="https://img.klavor.com/2019/03/javap-i-plus-plus-07.png" alt="将第2个int型的本地变量推送至栈顶"></p><ul><li><strong>第四步指令：iinc          1, 1</strong></li></ul><p>将第2个本地变量自增1</p><p><img src="https://img.klavor.com/2019/03/javap-i-plus-plus-08.png" alt="将第2个本地变量自增1"></p><ul><li><strong>第五步指令：istore_1</strong></li></ul><p>将栈顶int型数值存入到第2个本地变量</p><p><img src="https://img.klavor.com/2019/03/javap-i-plus-plus-09.png" alt="将栈顶int型数值存入到第2个本地变量"></p><p>根据以上的步骤可知此时的第2个本地变量的值应该是0，而i就是这第二个本地变量，因此i = 0。</p><h3 id="后话"><a href="#后话" class="headerlink" title="后话"></a>后话</h3><p>很多事情都没有想象中那么简单，有时候觉得理所当然的事情，可能因为存在本质上的差别和个体上的差异而导致了不相同的结果，而此时，应该怀揣着求之与探索的精神，去追寻其根源，从而才能够从根本上去解决问题。</p><h3 id="补充说明"><a href="#补充说明" class="headerlink" title="补充说明"></a>补充说明</h3><p>当执行了istore_n指令之后其实栈中的值应该是要弹出的，但是画图的时候没画对，现在也不想重新再画了，所以这一点需要注意一下，在这里做补充说明。</p>]]></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;figure class=&quot;hi</summary>
      
    
    
    
    <category term="dev" scheme="https://www.klavor.com/categories/dev/"/>
    
    
    <category term="Java" scheme="https://www.klavor.com/tags/Java/"/>
    
    <category term="字节码" scheme="https://www.klavor.com/tags/%E5%AD%97%E8%8A%82%E7%A0%81/"/>
    
    <category term="探索发现" scheme="https://www.klavor.com/tags/%E6%8E%A2%E7%B4%A2%E5%8F%91%E7%8E%B0/"/>
    
    <category term="反汇编" scheme="https://www.klavor.com/tags/%E5%8F%8D%E6%B1%87%E7%BC%96/"/>
    
  </entry>
  
  <entry>
    <title>「吉他谱」天使的项链_野人看夕阳</title>
    <link href="https://www.klavor.com/music/20190220-320.html"/>
    <id>https://www.klavor.com/music/20190220-320.html</id>
    <published>2019-02-19T16:00:00.000Z</published>
    <updated>2025-09-25T02:33:37.861Z</updated>
    
    <content type="html"><![CDATA[<p>去年还是前年的什么时候来着，请同事帮我扒了一首野人看夕阳唱的天使的项链的谱子，歌曲很好听，另外一首汽配厂我也非常推荐。经过了很长的时间之后我差一点忘记了这首歌曲怎么弹了，还好慢慢琢磨和回想了一下终于又将曲谱补齐了。为了给热爱音乐的广大网友们做出一些贡献，所以花了整整一晚上的时间把这首天使的项链制作成谱共享出来供热爱音乐的小伙伴们下载。因为是第一次制作吉他谱，会有很多不足之处，还望指教。也希望能与志同道合的小伙伴们多多交流。感谢！！</p><p><img src="https://img.klavor.com/2019/03/angel-necklace-01.png" alt="天使的项链-野人看夕阳"></p><p><img src="https://img.klavor.com/2019/03/angel-necklace-02.png" alt="天使的项链-野人看夕阳"></p><p>如果需要GTP格式吉他谱的朋友欢迎留言，后期也会在本文里附上下载链接，再次谢谢大家的支持！！！</p><hr><embed src="//music.163.com/style/swf/widget.swf?sid=35032325&amp;type=2&amp;auto=0&amp;width=320&amp;height=66" width="340" height="86" allownetworking="all">]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;去年还是前年的什么时候来着，请同事帮我扒了一首野人看夕阳唱的天使的项链的谱子，歌曲很好听，另外一首汽配厂我也非常推荐。经过了很长的时间之后我差一点忘记了这首歌曲怎么弹了，还好慢慢琢磨和回想了一下终于又将曲谱补齐了。为了给热爱音乐的广大网友们做出一些贡献，所以花了整整一晚上的</summary>
      
    
    
    
    <category term="music" scheme="https://www.klavor.com/categories/music/"/>
    
    
    <category term="吉他谱" scheme="https://www.klavor.com/tags/%E5%90%89%E4%BB%96%E8%B0%B1/"/>
    
    <category term="天使的项链" scheme="https://www.klavor.com/tags/%E5%A4%A9%E4%BD%BF%E7%9A%84%E9%A1%B9%E9%93%BE/"/>
    
    <category term="野人看夕阳" scheme="https://www.klavor.com/tags/%E9%87%8E%E4%BA%BA%E7%9C%8B%E5%A4%95%E9%98%B3/"/>
    
  </entry>
  
  <entry>
    <title>「五月天」天使</title>
    <link href="https://www.klavor.com/music/20190511-540.html"/>
    <id>https://www.klavor.com/music/20190511-540.html</id>
    <published>2019-02-19T16:00:00.000Z</published>
    <updated>2025-09-25T02:33:37.861Z</updated>
    
    <content type="html"><![CDATA[<h3 id="吉他谱"><a href="#吉他谱" class="headerlink" title="吉他谱"></a>吉他谱</h3><p><img src="https://img.klavor.com/2019/05/2019051107111624.png" alt="天使"></p><p><img src="https://img.klavor.com/2019/05/2019051107112393.png" alt="天使"></p><h3 id="吉他弹唱"><a href="#吉他弹唱" class="headerlink" title="吉他弹唱"></a>吉他弹唱</h3><p>暂无</p><h3 id="歌词"><a href="#歌词" class="headerlink" title="歌词"></a>歌词</h3><p>你就是我的天使<br>保护着我的天使<br>从此我再没有忧伤<br>你就是我的天使<br>给我快乐的天使<br>甚至我学会了飞翔<br>飞过人间的无常<br>才懂爱才是宝藏<br>不管世界变得怎麽样<br>只要有你就会是天堂<br>像孩子依赖着肩膀<br>像眼泪依赖着脸庞<br>你就像天使一样<br>给我依赖给我力量<br>像诗人依赖着月亮<br>像海豚依赖海洋<br>你是天使你是天使<br>你是我最初和最后的天堂</p>]]></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;img src=&quot;https://img.klavor.com/2019/05/2019051107111624.png&quot; alt</summary>
      
    
    
    
    <category term="music" scheme="https://www.klavor.com/categories/music/"/>
    
    
    <category term="吉他谱" scheme="https://www.klavor.com/tags/%E5%90%89%E4%BB%96%E8%B0%B1/"/>
    
    <category term="天使" scheme="https://www.klavor.com/tags/%E5%A4%A9%E4%BD%BF/"/>
    
    <category term="五月天" scheme="https://www.klavor.com/tags/%E4%BA%94%E6%9C%88%E5%A4%A9/"/>
    
  </entry>
  
  <entry>
    <title>「开源文档」Android JsBridge使用教程</title>
    <link href="https://www.klavor.com/dev/20190219-307.html"/>
    <id>https://www.klavor.com/dev/20190219-307.html</id>
    <published>2019-02-18T16:00:00.000Z</published>
    <updated>2025-09-25T02:33:37.821Z</updated>
    
    <content type="html"><![CDATA[<h2 id="如何使用JsBridge"><a href="#如何使用JsBridge" class="headerlink" title="如何使用JsBridge?"></a>如何使用JsBridge?</h2><h3 id="Js调用Android原生"><a href="#Js调用Android原生" class="headerlink" title="Js调用Android原生"></a>Js调用Android原生</h3><ul><li><strong>对于Android开发者</strong></li></ul><ol><li>创建Api功能类</li></ol><p>如需新增一个新的功能类提供给Js调用，则自定义一个类并实现JsApi接口，然后在此类中定义具有一个JsContext形参的方法，并通过@JsAnnotation注解此方法，以表明此方法是提供给Js调用。</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="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">LogJsApi</span> <span class="keyword">implements</span> <span class="title">JsApi</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@JsAnnotation</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">d</span><span class="params">(JsContext jsContext)</span> </span>&#123;</span><br><span class="line">        Log.d(jsContext.get(<span class="string">&quot;tag&quot;</span>, <span class="string">&quot;undefine&quot;</span>), jsContext.get(<span class="string">&quot;msg&quot;</span>, <span class="string">&quot;undefine&quot;</span>));</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="meta">@JsAnnotation</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">i</span><span class="params">(JsContext jsContext)</span> </span>&#123;</span><br><span class="line">        Log.i(jsContext.get(<span class="string">&quot;tag&quot;</span>, <span class="string">&quot;undefine&quot;</span>), jsContext.get(<span class="string">&quot;msg&quot;</span>, <span class="string">&quot;undefine&quot;</span>));</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ol start="2"><li>在JsApiMapping中声明</li></ol><p>在JsApiMapping类中的buildMapping()方法里通过mApiMapping.put(<em>功能名称</em>, <em>功能类</em>)新增一个功能类。</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">JsApiMapping</span> </span>&#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> HashMap&lt;String, Class&lt;? extends JsApi&gt;&gt; mApiMapping;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="title">JsApiMapping</span><span class="params">()</span> </span>&#123;</span><br><span class="line"></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> HashMap&lt;String, Class&lt;? extends JsApi&gt;&gt; getApiMapping() &#123;</span><br><span class="line">        <span class="keyword">if</span> (mApiMapping == <span class="keyword">null</span>) &#123;</span><br><span class="line">            <span class="keyword">synchronized</span> (JsApiMapping.class) &#123;</span><br><span class="line">                <span class="keyword">if</span> (mApiMapping == <span class="keyword">null</span>) &#123;</span><br><span class="line">                    mApiMapping = <span class="keyword">new</span> HashMap&lt;&gt;();</span><br><span class="line">                    buildMapping();</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> mApiMapping;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">buildMapping</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        mApiMapping.put(<span class="string">&quot;log&quot;</span>, LogJsApi.class);</span><br><span class="line">        mApiMapping.put(<span class="string">&quot;dialog&quot;</span>, DialogJsApi.class);</span><br><span class="line">        mApiMapping.put(<span class="string">&quot;nativeJs&quot;</span>, NativeJsApi.class);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>完成以上步骤之后，在程序运行时会根据 功能名称  和其中的方法名来生成一个可供js调用的函数，如：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">jsApi.log.d(arg)</span><br></pre></td></tr></table></figure><p>而调用函数需要传递的参数应根据功能类提供者所定义的参数格式为主。</p><ol start="3"><li>方法回调</li></ol><p>当提供给Js的方法被调用时，会传入一个JsContext对象的实参，此实参可以通过get()和put()方法进行数据的读取和写入，也可通过调用这个对象的success(),cancel(),error()方法来回调Js。</p><ul><li><strong>对于Web开发者</strong></li></ul><ol><li>调用Android原生代码</li></ol><p>Web开发人员可以通过如下方式调用原生代码：</p><figure class="highlight javascript"><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">jsApi.log.d(&#123;</span><br><span class="line">    <span class="attr">tag</span> : <span class="string">&#x27;kqt&#x27;</span>,</span><br><span class="line">    <span class="attr">msg</span> : arg</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>同时也可以通过另外一种形式调用：</p><figure class="highlight javascript"><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="function"><span class="keyword">function</span> <span class="title">log</span>(<span class="params">level, arg</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (level == <span class="number">0</span>) &#123;</span><br><span class="line">        jsApi.log.d(&#123;</span><br><span class="line">            <span class="attr">tag</span> : <span class="string">&#x27;kqt&#x27;</span>,</span><br><span class="line">            <span class="attr">msg</span> : arg</span><br><span class="line">        &#125;)</span><br><span class="line">    &#125; <span class="keyword">else</span> <span class="keyword">if</span> (level == <span class="number">1</span>) &#123;</span><br><span class="line">        jsApi.log.i(&#123;</span><br><span class="line">            <span class="attr">tag</span> : <span class="string">&#x27;cmf&#x27;</span>,</span><br><span class="line">            <span class="attr">msg</span> : arg</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><p>Web开发者可以根据需求自行灵活运用。</p><ol start="2"><li>方法回调实现</li></ol><p>当需要和Android原生代码之间进行交互的时候，就需要通过回调实现，但回调是否生效还需要看功能类提供者是否实现了回调功能。</p><p>Js中方法回调的书写形式如下：</p><figure class="highlight javascript"><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="function"><span class="keyword">function</span> <span class="title">show</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">    jsApi.dialog.show(&#123;</span><br><span class="line">        <span class="attr">title</span> : <span class="string">&quot;警告&quot;</span>,</span><br><span class="line">        <span class="attr">message</span> : <span class="string">&quot;请不要点击取消!&quot;</span>,</span><br><span class="line">        <span class="attr">positive</span> : <span class="string">&quot;知道了&quot;</span>,</span><br><span class="line">        <span class="attr">negative</span> : <span class="string">&quot;我就要&quot;</span>,</span><br><span class="line">        <span class="attr">success</span> : <span class="function"><span class="keyword">function</span>(<span class="params">arg</span>) </span>&#123;</span><br><span class="line">            alert(arg.msg);</span><br><span class="line">        &#125;,</span><br><span class="line">        <span class="attr">cancel</span> : <span class="function"><span class="keyword">function</span>(<span class="params">arg</span>) </span>&#123;</span><br><span class="line">            alert(arg.msg);</span><br><span class="line">        &#125;,</span><br><span class="line">        <span class="attr">error</span> : <span class="function"><span class="keyword">function</span>(<span class="params">arg, err</span>) </span>&#123;</span><br><span class="line">            alert(err);</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><p>参数中具体返回的数据主要由功能类提供者所决定。</p><h3 id="Android原生调用Js"><a href="#Android原生调用Js" class="headerlink" title="Android原生调用Js"></a>Android原生调用Js</h3><ul><li><strong>对于Android开发者</strong></li></ul><ol><li>通过KWebView的nativeJs方法进行调用Js函数</li></ol><p>nativeJs方法有三个形参。第一个形参是指Js的函数名；第二个形参是指传递给Js的数据；第三个形参是指回调的处理。</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">findViewById(R.id.btn).setOnClickListener(<span class="keyword">new</span> View.OnClickListener() &#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onClick</span><span class="params">(View v)</span> </span>&#123;</span><br><span class="line">        JsContext jsContext = <span class="keyword">new</span> JsContext(kwv.getWebViewProxy());</span><br><span class="line">        kwv.nativeJs(<span class="string">&quot;test&quot;</span>, jsContext, <span class="keyword">new</span> NativeCallback() &#123;</span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">success</span><span class="params">(JsContext jsContext)</span> </span>&#123;</span><br><span class="line">                Log.d(<span class="string">&quot;cmf&quot;</span>, <span class="string">&quot;success...&quot;</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="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">cancel</span><span class="params">(JsContext jsContext)</span> </span>&#123;</span><br><span class="line">                Log.d(<span class="string">&quot;cmf&quot;</span>, <span class="string">&quot;cancel...&quot;</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="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">error</span><span class="params">(JsContext jsContext)</span> </span>&#123;</span><br><span class="line">                Log.d(<span class="string">&quot;cmf&quot;</span>, <span class="string">&quot;error...&quot;</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></pre></td></tr></table></figure><ol start="2"><li>方法回调</li></ol><p>如步骤1中调用nativeJs()方法时的第三个形参，只需要在其中处理回调即可。最终是否能被成功回调，需由Web开发者实现。</p><ul><li><strong>对于Web开发者</strong></li></ul><ol><li>定义一个函数</li></ol><p>如果需要添加一个给Android原生代码调用的函数，则需要在代码中进行定义。如下：</p><figure class="highlight javascript"><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="function"><span class="keyword">function</span> <span class="title">test</span>(<span class="params">arg, rtn</span>) </span>&#123;</span><br><span class="line">    rtn.success(arg);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>函数体内可根据具体需求来实现。其中，第一个形参是指Android原生代码传过来的数据；第二个形参是指回调函数的对象，里面包含了success()，cancel()和error()三个回调方法。</p><h2 id="不足之处"><a href="#不足之处" class="headerlink" title="不足之处"></a>不足之处</h2><p>JsBridge库中，暂未实现监听的功能，目前仅限于一次回调，如Js调用Android原生代码后回调了一次之后，第二次再调用回调方法将不会再生效，因为此时回调的对象已经移除出回调的集合了。</p><h2 id="关于我"><a href="#关于我" class="headerlink" title="关于我"></a>关于我</h2><p>邮箱: <a href="mailto:&#x6c;&#101;&#x65;&#64;&#107;&#x6c;&#97;&#118;&#x6f;&#114;&#x2e;&#x63;&#111;&#x6d;">&#x6c;&#101;&#x65;&#64;&#107;&#x6c;&#97;&#118;&#x6f;&#114;&#x2e;&#x63;&#111;&#x6d;</a><br /><br>扣扣: 2262693733<br /><br>微博: <a href="http://weibo.com/lihuan1991">http://weibo.com/lihuan1991</a><br /><br>主页: <a href="https://www.klavor.com/">https://www.klavor.com</a></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;如何使用JsBridge&quot;&gt;&lt;a href=&quot;#如何使用JsBridge&quot; class=&quot;headerlink&quot; title=&quot;如何使用JsBridge?&quot;&gt;&lt;/a&gt;如何使用JsBridge?&lt;/h2&gt;&lt;h3 id=&quot;Js调用Android原生&quot;&gt;&lt;a href=</summary>
      
    
    
    
    <category term="dev" scheme="https://www.klavor.com/categories/dev/"/>
    
    
    <category term="Android" scheme="https://www.klavor.com/tags/Android/"/>
    
    <category term="Javascript" scheme="https://www.klavor.com/tags/Javascript/"/>
    
    <category term="开源文档" scheme="https://www.klavor.com/tags/%E5%BC%80%E6%BA%90%E6%96%87%E6%A1%A3/"/>
    
    <category term="JsBridge" scheme="https://www.klavor.com/tags/JsBridge/"/>
    
  </entry>
  
  <entry>
    <title>「解决方案」命令行执行flutter doctor无响应原因追踪及解决</title>
    <link href="https://www.klavor.com/dev/20190117-163.html"/>
    <id>https://www.klavor.com/dev/20190117-163.html</id>
    <published>2019-01-16T16:00:00.000Z</published>
    <updated>2025-11-01T00:45:46.336Z</updated>
    
    <content type="html"><![CDATA[<h2 id="问题再现"><a href="#问题再现" class="headerlink" title="问题再现"></a>问题再现</h2><p>最近在学习Flutter开发，在一次配置环境的过程中遇到了一个比较尴尬的坑，不过最终还是把这个坑给填掉了，再此进行一些分享，希望后来者遇到同样的问题时可以轻松的解决。<br>从下图中可以看出，前面几条<code>flutter doctor</code>命令执行的时候总是未响应，通过各种方式执行都是一样的结果，但是dart命令是能够正常执行。起初还以为是环境变量配置的有问题，但是后来把环境变量改了又改，并且把flutter包换了又换，但是现象一直未得到解决。</p><p><img src="https://img.klavor.com/2019/03/flutter-comman-not-response-when-git-installed-01.png" alt="flutter-comman-not-response-when-git-installed"></p><h2 id="解决问题"><a href="#解决问题" class="headerlink" title="解决问题"></a>解决问题</h2><h3 id="寻求网络帮助"><a href="#寻求网络帮助" class="headerlink" title="寻求网络帮助"></a>寻求网络帮助</h3><p>遇到这种难题第一时间想到的便是百度，但是各种关键词搜索了一番之后，竟然没有找到一篇关于这种现象的解决方案，大部分都是flutter命令使用教程，如用<code>flutter doctor</code>去查看环境是否配置完成，或者通过<code>flutter doctor --android-licenses</code>命令去接受Android SDK的一些协议许可。<br>后来，又尝试了必应和Google搜索，也无果之后，放弃了通过网络寻求帮助解决的方法。</p><h3 id="大胆试错"><a href="#大胆试错" class="headerlink" title="大胆试错"></a>大胆试错</h3><p>由于只有flutter的命令执行的时候无响应，所以起初认为是程序包有问题。于是通过再次解压程序压缩包和配置环境变量之后，问题仍然存在。<br>随后，判断了不是程序包的问题之后开始去监控应用进程的变化。</p><ul><li>任务管理器<br>从图中可以发现在<strong>任务管理器</strong>的详细信息栏里看到了很多个git正在执行，并且很卡。</li></ul><p><img src="https://img.klavor.com/2019/03/flutter-comman-not-response-when-git-installed-03.png" alt="flutter-comman-not-response-when-git-installed"></p><ul><li>性能<br>从性能栏页面底部的<strong>打开资源监视器</strong>进入到资源监控页面</li></ul><p><img src="https://img.klavor.com/2019/03/flutter-comman-not-response-when-git-installed-04.png" alt="flutter-comman-not-response-when-git-installed"></p><ul><li>资源监视器<br>然后在网络一栏看到了多个<strong>git</strong>和一个<strong>git-remote-http</strong>在运行，并且<strong>git-remote-http</strong>的地址指向了**<em><a href="https://ec2-37-112--117-223.ap-southeast-01.compute.amazonaws.com/">https://ec2-37-112--117-223.ap-southeast-01.compute.amazonaws.com</a>**</em>。这里的图片是后来截的，所以看不到那个程序和地址了。</li></ul><p><img src="https://img.klavor.com/2019/03/flutter-comman-not-response-when-git-installed-06.png" alt="flutter-comman-not-response-when-git-installed"></p><h3 id="根源"><a href="#根源" class="headerlink" title="根源"></a>根源</h3><p>到这里，可以猜到很可能是由于git导致的问题，但是先前安装过flutter都没有问题，这一次重装系统之后就突然有问题了。所以就尝试着把git软件给删除并重新安装，然后奇迹的发现了<code>flutter doctor</code>命令可以正常执行了。<br>于是又倒退回去复现了一下问题，发现是安装git的时候选项选的有问题导致了和flutter冲突。<br>如下图，选择了<strong>Use Window’s default console window</strong>的选项来安装git软件之后，git bash是直接用的window的命令窗口来执行命令。正是因为选中了这个选项所以导致flutter命令无响应的问题。<br>所以如果你出现了和我一样的问题可以尝试重新安装git软件，并在这一步选择<strong>Use MinTTY</strong>的选项来安装。</p><p><img src="https://img.klavor.com/2019/03/flutter-comman-not-response-when-git-installed-02.png" alt="flutter-comman-not-response-when-git-installed"></p><h2 id="完美填坑"><a href="#完美填坑" class="headerlink" title="完美填坑"></a>完美填坑</h2><p>经过不断的试错，终于将这个问题解决了，flutter命令也可以正常执行了。如图，通过VSCode开发工具可以正常的执行<code>flutter create hello_flutter</code>创建新的flutter项目。</p><p><img src="https://img.klavor.com/2019/03/flutter-comman-not-response-when-git-installed-05.png" alt="flutter-comman-not-response-when-git-installed"></p><h2 id="写在最后"><a href="#写在最后" class="headerlink" title="写在最后"></a>写在最后</h2><p>遇到问题要大胆试错，只要不断的尝试就会离问题的起因更近，最后找到解决问题的办法。如果你的flutter遇到了相同的问题而又不是由于git导致的话，也可以通过类似的方式不断试错并找到最终的解决方案。也欢迎各位同行可以在评论里分享自己解决问题的方法。<br>乐于分享，共同进步。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;问题再现&quot;&gt;&lt;a href=&quot;#问题再现&quot; class=&quot;headerlink&quot; title=&quot;问题再现&quot;&gt;&lt;/a&gt;问题再现&lt;/h2&gt;&lt;p&gt;最近在学习Flutter开发，在一次配置环境的过程中遇到了一个比较尴尬的坑，不过最终还是把这个坑给填掉了，再此进行一些分享，</summary>
      
    
    
    
    <category term="dev" scheme="https://www.klavor.com/categories/dev/"/>
    
    
    <category term="flutter" scheme="https://www.klavor.com/tags/flutter/"/>
    
    <category term="git" scheme="https://www.klavor.com/tags/git/"/>
    
    <category term="解决方案" scheme="https://www.klavor.com/tags/%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88/"/>
    
    <category term="命令行无响应" scheme="https://www.klavor.com/tags/%E5%91%BD%E4%BB%A4%E8%A1%8C%E6%97%A0%E5%93%8D%E5%BA%94/"/>
    
  </entry>
  
</feed>
