<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>码工作坊</title>
	<atom:link href="http://www.khotyn.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.khotyn.com</link>
	<description>你不必害怕沉沦堕落，只消你能不断的自拔与更新</description>
	<lastBuildDate>Mon, 30 Apr 2012 09:37:39 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>一个velocity.log引发的问题</title>
		<link>http://www.khotyn.com/2012/03/12/velocity-log/</link>
		<comments>http://www.khotyn.com/2012/03/12/velocity-log/#comments</comments>
		<pubDate>Mon, 12 Mar 2012 15:35:26 +0000</pubDate>
		<dc:creator>khotyn</dc:creator>
				<category><![CDATA[Java基础]]></category>
		<category><![CDATA[编程]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Velocity]]></category>

		<guid isPermaLink="false">http://www.khotyn.com/?p=818</guid>
		<description><![CDATA[最近在项目中采用了velocity最一些简单的规则做动态解析，大概的代码如下（经过一定程度简化）：

这段代码在开发环境下运行地一直很正常，直到昨天部署到了测试环境了，引发了一个诡异的NullPointException
原因分析
首先经过一位同事的Debug，发现在做evaluate，把模板解析成NodeTree，获取parser的过程中，parserPool的值是null，从而引发了NullPointException，代码如下：

正常情况下，velocity初始化之后，parserPool都应该正常初始化了，不应该出现parserPool为null的情况，只有一种可能是，parserP [...]]]></description>
			<content:encoded><![CDATA[<p>最近在项目中采用了velocity最一些简单的规则做动态解析，大概的代码如下（经过一定程度简化）：</p>
<p><img src="http://farm8.staticflickr.com/7043/6976270723_e25b6b88b2_z.jpg" alt="image" /></p>
<p>这段代码在开发环境下运行地一直很正常，直到昨天部署到了测试环境了，引发了一个诡异的<code>NullPointException</code></p>
<h2>原因分析</h2>
<p>首先经过一位同事的Debug，发现在做evaluate，把模板解析成<code>NodeTree</code>，获取<code>parser</code>的过程中，<code>parserPool</code>的值是<code>null</code>，从而引发了<code>NullPointException</code>，代码如下：</p>
<p><img src="http://farm8.staticflickr.com/7062/6830153340_68a3d32c4f_b.jpg" alt="image" width="100%"/></p>
<p>正常情况下，velocity初始化之后，parserPool都应该正常初始化了，不应该出现<code>parserPool</code>为<code>null</code>的情况，只有一种可能是，<code>parserPool</code>初始化失败了。</p>
<p>继续跟踪velocity初始化的代码：</p>
<p><img src="http://farm8.staticflickr.com/7065/6976280187_c71affdfd1_b.jpg" alt="image" width="100%"/></p>
<p>还没有debug到<code>initializeParserPool()</code>这一步，在<code>initializeLog()</code>这一步velocity就抛出了异常：</p>
<pre class="brush: java; title: ; notranslate">FileNotFoundException: velocity.log (Permission denied)
</pre>
<p>那么分析一下velocity日志初始化的过程：</p>
<ol>
<li>velocity的日志系统的初始化都在<code>LogManager.createLogChute()这个方法里面</code>。</li>
<li>首先，在velocity的jar里面的velocity.properties，配置了一个
<pre class="brush: java; title: ; notranslate">
runtime.log.logsystem.class = org.apache.velocity.runtime.log.AvalonLogChute,
org.apache.velocity.runtime.log.Log4JLogChute,
org.apache.velocity.runtime.log.CommonsLogLogChute,
org.apache.velocity.runtime.log.ServletLogChute,
org.apache.velocity.runtime.log.JdkLogChute
</pre>
<p>velocity初始化的时候，会遍历这个列表，一个个尝试，而在我们的项目中，有log4j，所以采用的就是第二个<code>org.apache.velocity.runtime.log.Log4JLogChute</code>。</li>
<li>在初始化<code>org.apache.velocity.runtime.log.Log4JLogChute</code>的过程中，velocity会再次去velocity.properties里面找<code>runtime.log = velocity.log</code>，就是运行时日志的路径，而log4j创建appender的时候，就直接采用<code>new File("velocity.log")</code>的方式在文件系统中创建一个日志文件。</li>
<li>大家知道<code>new File("velocity.log")</code>这种方式是在<code>usr.dir</code>下面直接创建文件的，由于我们的应用是jetty，<code>usr.dir</code>指向的目录是<code>JETTY_HOME</code>。</li>
</ol>
<p>那么，问题的原因应该大概清楚了：</p>
<ul>
<li>在测试环境上jetty安装的目录是在/usr下面的，普通的用户是对/usr目录没有写权限的，所以出现了Permission Denied</li>
<li>但是对于本机开发环境，尽管jetty也是安装在/usr下面，但是由于/usr目录的权限已经被手工的设置为了任何人都能访问，所以没有出现了Permission Deinied的情况。</li>
</ul>
<h2>问题解决</h2>
<p>只需要关闭掉velocity的运行时日志，在<code>ve.init()</code>前加上以下一段代码即可：</p>
<p><pre class="brush: java; title: ; notranslate">
ve.setProperty(RuntimeConstants.RUNTIME_LOG_LOGSYSTEM, new NullLogChute());
</pre>
</p>
<h2>总结</h2>
<p>大家以后再使用velocity时候，需要特别注意下<code>velocity.log</code>的这个问题，我到Google上搜索了一把，其实这个问题还是挺普遍的，包括之前一位同事在去年做jetty迁移的时候也遇到了同样的问题，总之，以后使用的时候小心吧。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.khotyn.com/2012/03/12/velocity-log/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>又拍？Flickr? Github才是最适合Geek的图床服务！</title>
		<link>http://www.khotyn.com/2012/03/08/github-for-picturing/</link>
		<comments>http://www.khotyn.com/2012/03/08/github-for-picturing/#comments</comments>
		<pubDate>Thu, 08 Mar 2012 12:57:40 +0000</pubDate>
		<dc:creator>khotyn</dc:creator>
				<category><![CDATA[编程]]></category>
		<category><![CDATA[Github]]></category>
		<category><![CDATA[随笔]]></category>

		<guid isPermaLink="false">http://www.khotyn.com/?p=814</guid>
		<description><![CDATA[Yupoo &#38; Flickr Sucks!
一直以来我都在为我的博客寻找最佳的图床服务，最开始用Wordpress自带的，但是明显一旦博客迁移起来太不方便。
后来我试了国内的又拍，不得不说，又拍真心不错，非常能满足我的要求，直到有一天我想要做一个命令行工具，希望可以通过这个工具直接上传图片到又拍上去，但是当我一次又一次尝试和又拍沟通获取他们的API Key而杳无音讯时，不得已，我又转而使用Flickr。
Flickr可以非常方便地申请到API  [...]]]></description>
			<content:encoded><![CDATA[<h2>Yupoo &amp; Flickr Sucks!</h2>
<p>一直以来我都在为我的博客寻找最佳的图床服务，最开始用Wordpress自带的，但是明显一旦博客迁移起来太不方便。</p>
<p>后来我试了国内的又拍，不得不说，又拍真心不错，非常能满足我的要求，直到有一天我想要做一个命令行工具，希望可以通过这个工具直接上传图片到又拍上去，但是当我一次又一次尝试和又拍沟通获取他们的API Key而杳无音讯时，不得已，我又转而使用Flickr。</p>
<p>Flickr可以非常方便地申请到API Key，于是我马上着手做了一个工具：Nausicca，但是前几天当我把一些带有透明背景的图片上传到Flickr上去以后，发现压缩后的图片透明背景已经没有了，阴影被黑色取代，再仔细研究一番后发现只能是Flickr Pro帐户才能够下载到原图，真是令人伤心。</p>
<h2>Github Rocks!</h2>
<p>直到昨天晚上，我在泡着脚，看着美女，突然发现其实可以用Github作为博客的图床服务，只需要做：</p>
<ul>
<li>在Github上建立一个公开的项目，这个项目专门用来上传图片用。</li>
<li>写一个脚本接受一张图片的路径，然后自动push到你的Github上。</li>
<li>当你把图片push到Github上去以后，以下地址<code>${project_address}/raw/master/${fileName}<br />
</code>便是图片对应的地址，其实<code>${project_address}</code>是你的项目的地址，<code>${fileName}</code>是你上传的图片的文件名。</li>
</ul>
<p>怎么样？简单吧，当然把图片放在Github上有一定的缺点：</p>
<ul>
<li>只有原图，没有其他的尺寸提供。</li>
<li>Github说不定什么时候就完全被墙了。</li>
</ul>
<p>当然，优点也是多多：</p>
<ul>
<li>有原图尺寸提供啊！</li>
<li>备份方便啊，只要clone一下就备份完成了！</li>
<li>够Geek啊，命令行上传多方便啊！</li>
</ul>
<p>当然，个人建议可以将Github和Flickr结合起来用，只需要原图的时候可以用Github，需要各种尺寸的图片的时候可以用Flickr（当然，你要手工压缩也可以嘛！这样就直接用Github吧）。</p>
<h2>The End</h2>
<p><img src="https://github.com/khotyn/Freyja/raw/master/61c0c922jw1dqrnnhl3efj.png" alt="image" /></p>
]]></content:encoded>
			<wfw:commentRss>http://www.khotyn.com/2012/03/08/github-for-picturing/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Lullaby &#8212; Loreena McKennit</title>
		<link>http://www.khotyn.com/2012/03/07/lullaby-loreena-mckennit/</link>
		<comments>http://www.khotyn.com/2012/03/07/lullaby-loreena-mckennit/#comments</comments>
		<pubDate>Wed, 07 Mar 2012 14:39:29 +0000</pubDate>
		<dc:creator>khotyn</dc:creator>
				<category><![CDATA[Life]]></category>

		<guid isPermaLink="false">http://www.khotyn.com/?p=809</guid>
		<description><![CDATA[事隔四年多，又听到了这首Loreena McKennit的《Lullaby》。其实第一次听到这首歌，吸引我的并不是Loreena McKennit的声音，而是这首歌中的诗歌朗诵部分，铿锵有力，震撼人心。
今天特地去找了一下，这首歌中的诗来自于英国诗人Willian Blake的诗集《Poetical Sketches》，诗的题目叫《Prolugue, intended for a dramatic piece of King Edward the Fourth》，朗诵这首诗的是Douglas Campbell。
这首歌的试听链接是：

歌词部分

O FOR a voice like  [...]]]></description>
			<content:encoded><![CDATA[<p>事隔四年多，又听到了这首Loreena McKennit的《Lullaby》。其实第一次听到这首歌，吸引我的并不是Loreena McKennit的声音，而是这首歌中的诗歌朗诵部分，铿锵有力，震撼人心。</p>
<p>今天特地去找了一下，这首歌中的诗来自于英国诗人<a href="http://zh.wikipedia.org/wiki/%E5%A8%81%E5%BB%89%C2%B7%E5%B8%83%E8%8E%B1%E5%85%8B">Willian Blake</a>的诗集<a href="http://en.wikipedia.org/wiki/Poetical_Sketches">《Poetical Sketches》</a>，诗的题目叫<a href="http://en.wikipedia.org/wiki/Poetical_Sketches#.27Prologue.2C_Intended_for_a_dramatic_piece_of_King_Edward_the_Fourth.27_and_.27Prologue_to_King_John.27">《Prolugue, intended for a dramatic piece of King Edward the Fourth》</a>，朗诵这首诗的是<a href="http://en.wikipedia.org/wiki/Douglas_Campbell_%28actor%29">Douglas Campbell</a>。</p>
<p>这首歌的试听链接是：</p>
<p><embed src="http://www.xiami.com/widget/0_1708800/singlePlayer.swf" type="application/x-shockwave-flash" width="257" height="33" wmode="transparent"></embed></p>
<p>歌词部分</p>
<blockquote>
<p>O FOR a voice like thunder, and a tongue</p>
<p>To drown the throat of war! When the senses</p>
<p>Are shaken, and the soul is driven to madness,</p>
<p>Who can stand? When the souls of the oppressed</p>
<p>Fight in the troubled air that rages, who can stand?</p>
<p>When the whirlwind of fury comes from the</p>
<p>Throne of God, when the frowns of His countenance</p>
<p>Drive the nations together, who can stand?</p>
<p>When Sin claps his broad wings over the battle,</p>
<p>And sails rejoicing in the flood of death;</p>
<p>When souls are torn to everlasting fire,</p>
<p>And fiends of hell rejoice upon the slain,</p>
<p>O who can stand? O who hath caused this?</p>
<p>O who can answer at the throne of God?</p>
<p>The Kings and Nobles of the land have done it!</p>
<p>Hear it not, Heaven, thy ministers have done it!</p>
<p></blockguote></p>
]]></content:encoded>
			<wfw:commentRss>http://www.khotyn.com/2012/03/07/lullaby-loreena-mckennit/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>ASM学习笔记</title>
		<link>http://www.khotyn.com/2012/03/06/asm_note/</link>
		<comments>http://www.khotyn.com/2012/03/06/asm_note/#comments</comments>
		<pubDate>Mon, 05 Mar 2012 16:32:01 +0000</pubDate>
		<dc:creator>khotyn</dc:creator>
				<category><![CDATA[JVM]]></category>
		<category><![CDATA[编程]]></category>
		<category><![CDATA[ASM]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Tool]]></category>
		<category><![CDATA[阅读笔记]]></category>

		<guid isPermaLink="false">http://www.khotyn.com/?p=802</guid>
		<description><![CDATA[ASM是什么？
简单地说，ASM是一个用于Java字节码操作的类库，它提供了对字节码上一层的抽象，即Java  [...]]]></description>
			<content:encoded><![CDATA[<h2>ASM是什么？</h2>
<p>简单地说，ASM是一个用于Java字节码操作的类库，它提供了对字节码上一层的抽象，即Java Class文件中的各个部分进行操作的API。ASM这个名字来自于C的关键字<code>__asm__</code>。</p>
<h2>ASM可以干什么？</h2>
<p>先来看一幅图，如下图：</p>
<p><img src="http://pic.yupoo.com/khotyn/BNeYTVrc/wShw7.png" alt="image" /></p>
<p>如果我们把我们平常从Java文件到运行的过程分成编译器和Java虚拟机两部分，那么Class文件就是两者之间产生联系的桥梁。一般情况下，Class文件是通过javac编译器产生的，然后通过类加载器加载到虚拟机内，再通过执行引擎去执行。现在有了ASM们就可以它的API直接生成符合Java虚拟机规范的Class字节流，这样，ASM做的事情一定程度上正是javac解释器做的工作。</p>
<p>那么，我们就可以通过ASM来实现诸如代码生成，代码混淆，代码转换等等以字节码为操作目标的工作。</p>
<h2>如何使用ASM</h2>
<p>ASM提供了两套API供使用者使用，一套叫Core API，是基于事件的方式对字节码进行处理；另一套叫Tree API，是基于对象的方式对字节码进行处理。如果你熟悉XML解析，那么实际上Core API就是SAX这种处理模式，而Tree API就是DOM这种处理模式。</p>
<h3>Core API</h3>
<p>使用Core API进行对字节码进行处理一般需要三个部分：</p>
<ul>
<li>一个事件的生产者，用于产生各种事件，通常这会是一个<code>ClassReader</code></li>
<li>一个事件的消费者，用于消费各种事件，通常这会是一个<code>ClassWriter</code></li>
<li>若干个事件的过滤器，这些过滤器可以对感兴趣的事件进行过滤来处理，这通常会是一些<code>ClassVisitor</code></li>
</ul>
<p>其处理过程如下图所示：</p>
<p><img src="http://pic.yupoo.com/khotyn/BNeLCEEB/157i6N.png" alt="image" /></p>
<p>看下面一个例子：</p>
<pre class="brush: java; title: ; notranslate">
public class ASMTest {
    public static void main(String[] args) throws IOException {
        FileInputStream fis = new FileInputStream(new File(&amp;ldquo;/Users/apple/Desktop/Test.class&amp;rdquo;));
        ClassReader cr = new ClassReader(fis);
        ClassWriter cw = new ClassWriter(cr, 0);
        ClassVisitor cv = new ClassVisitor(Opcodes.ASM4, cw) {
            public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
                if ((access &amp;amp; Opcodes.ACC_PUBLIC) != 0) {
                    access = (access ^ Opcodes.ACC_PUBLIC) + Opcodes.ACC_PRIVATE;
                }&lt;/p&gt;

            return cv.visitMethod(access, name, desc, signature, exceptions);
        }
    };
    cr.accept(cv, 0);
    FileOutputStream fos = new FileOutputStream(new File(&quot;/Users/apple/Desktop/result/Test.class&quot;));
    fos.write(cw.toByteArray());
    fos.flush();
    fos.close();
   }
}
</pre>
<p>这个例子先是从文件流中读入一个待处理的Class文件，然后new了<code>ClassReader</code>，作为事件源，然后new了一个<code>ClassWriter</code>，作为事件的接收者，还实现了一个<code>ClassVisitor</code>，这个<code>ClassVisitor</code>将所有的public方法变成了private的方法。接着通过调用<code>cr.accept</code>方法来触发事件，通过<code>cw.toByteArray</code>来拿到处理后的字节码并且输出到文件。</p>
<p>从前面的图以及代码可以看出，采用Core API处理字节码，其实就是通过继承<code>ClassVisitor</code>，并且覆盖<code>ClassVisitor</code>中的对应的方法来对特定的事件进行处理的过程，其实这里的事件基本上对应到了Class文件中的各个部分，除了常量池部分，所以如果了解了Class文件的结构，那么用Core API处理起来应该得心应手。</p>
<p>除了<code>ClassVisitor</code>之外，Core API还提供了<code>MethodVisitor</code>、<code>FieldVisitor</code>、<code>AnnotationVisitor</code>来对方法，字段和注解操作。</p>
<h3>Tree API</h3>
<p>前面说过，Tree API是基于对象的方式来处理字节码，Tree API的最核心的一个类就是<code>ClassNode</code>，它就代表了一个Java Class文件，它里面的属性对应到了一个Class文件的各个部分，如下图：</p>
<p><img src="http://farm8.staticflickr.com/7181/6806377254_4499227d46.jpg" alt="image" /></p>
<p>使用Tree API来创建一个类的过程，其实就是设置ClassNode的属性的一个过程，一个例子如下：</p>
<pre class="brush: java; title: ; notranslate">
public class ASMTest {
    @SuppressWarnings(&quot;unchecked&quot;)
    public static void main(String[] args) throws IOException {
        ClassNode cn = new ClassNode();
        cn.name = &quot;ASMInterface&quot;;
        cn.access = Opcodes.ACC_PUBLIC + Opcodes.ACC_ABSTRACT + Opcodes.ACC_INTERFACE;
        cn.superName = Type.getInternalName(Object.class);
        cn.interfaces.add(Type.getInternalName(Runnable.class));
        cn.version = Opcodes.V1_6;
        cn.sourceFile = &quot;ASMInterface.java&quot;;
        MethodNode mn = new MethodNode(Opcodes.ACC_PUBLIC + Opcodes.ACC_ABSTRACT + Opcodes.ACC_SYNTHETIC, &quot;stop&quot;, &quot;()V&quot;, null, null);
        cn.methods.add(mn);
        ClassWriter cw = new ClassWriter(0);
        cn.accept(cw);
        FileOutputStream fos = new FileOutputStream(new File(&quot;/Users/apple/Desktop/result/ASMInterface.class&quot;));
        fos.write(cw.toByteArray());
        fos.flush();
        fos.close();
    }
}
</pre>
<p>上面的代码，新建了一个ClassNode，用来创建一个继承了<code>java.lang.Runnable</code>接口的接口<code>ASMInterface</code>，它包含了一个方法<code>public void stop()</code>，最后将生成的字节码通过<code>ClassWriter</code>输出到文件。</p>
<p>和创建类一样，通过Tree API修改一个类也只需要修改<code>ClassNode</code>的属性。如果你要修改方法，字段或者注解，那么可以通过<code>ClassNode</code>拿到<code>MethodNode</code>、<code>FieldNode</code>、<code>AnnotationNode</code>来进行对应的修改。</p>
<h3>什么时候使用Core API，什么时候使用Tree API？</h3>
<p>Core API和Tree API其实各有优缺点：</p>
<ul>
<li>Core API的优势是处理速度快，占用内存小，因为它不需要在内存中将整个Class文件表示出来，缺点是基于事件的方式处理，如果错过一个事件，那么就是过了这个村，没有这个店了，这样如果需要实现诸如将特定<code>GOTO</code>出插入其他指令，就会比较麻烦，因为<code>GOTO</code>可以跳转到之前的指令，但是之前的指令的事件已经被处理了，到时候只能再次触发一遍事件来处理。</li>
<li>Tree API的优势就是Core API的劣势，对于上面提到的<code>GOTO</code>的这种情况，Tree API处理起来就轻松了很多，因为在内存中有Class文件的完整表示，随便什么样的顺序去改都是没有问题的。缺点就是占用内存比较大，处理速度比较慢。</li>
</ul>
<p>如果你查看<code>ClassNode</code>的源代码，那么可以发现<code>ClassNode</code>事实上继承了<code>ClassVisitor</code>。那么，我们就可以将在实际操作的时候将Core API和Tree API结合起来，灵活运用各自的优缺点去解决问题。</p>
<h3>辅助工具类</h3>
<p>ASM除了提供了Core API和Tree API两套API以外，还提供了几个比较实用的工具类</p>
<h4>CheckClassAdapter</h4>
<p>实际上，用ASM生成的字节码可能并不符合Java虚拟机规范的，如果需要检查生成的字节码符不符合规范，那么可以用<code>CheckClassAdapter</code>作为一个<code>ClassVisitor</code>加入到<code>ClassVisitor</code>链中，如果字节码不符合规范，那么<code>CheckClassAdapter</code>就会抛出异常。</p>
<h4>ASMifier</h4>
<p>ASM作为一个字节码操作工具，相对于其他的字节码操作工具，比如Javassist，写起来还是比较烦琐的，如果你已经有了一个Class文件，想要知道如何通过ASM生成这个Class文件，那么就可以直接用<code>ASMifier</code>这个类，通过这个类，可以直接生成出生成目标类的ASM代码，一定程度上简化了直接手写ASM代码的繁琐工作。</p>
<p>ASMifier可以直接通过命令行来使用，比如那我们刚才生成的那个<code>ASMInterface</code>为例：</p>
<p><img src="http://farm8.staticflickr.com/7045/6810028932_73b97e7893_z.jpg" alt="image" /></p>
<p>可以看到<code>ASMifier</code>直接将生成<code>ASMInterface</code>所需要的ASM代码直接打印出来了。</p>
<h4>LocalVariableSorter</h4>
<p>假设你要往一个方法里面加入一个本地变量，那么你就需要将这个变量加入到本地变量表的最后，遗憾的是，本地变量表的大小只有当你在调用<code>visitMaxs</code>的时候才知道，通常，这个时候已经到了方法的结尾处，再想加本地变量已经晚了，现在通过<code>LocalVariableSorter</code>这个<code>ClassVisitor</code>，你就可以非常简单插入一个本地变量。</p>
<h2>总结</h2>
<p>ASM作为其他很多的代码生成工具的所依赖的类库，其处理速度快，体积小，并且通过提供了对Class文件各个部分的操作API，可以让你对Class文件进行最细致的修改。但是对于大段大段的代码生成，使用ASM还是显得有些繁琐，即使有<code>ASMifier</code>，还是不如Javassist来的直观，使用过程中最好根据自己的需求进行取舍。</p>
<p>其他说明：</p>
<ul>
<li>这篇文章中的代码都是基于ASM 4.0的，ASM 4.0和ASM 3.X的代码略有不同，使用过程中需要注意。</li>
<li>ASM的官方网站是：<a href="http://asm.ow2.org/">http://asm.ow2.org/</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.khotyn.com/2012/03/06/asm_note/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>魔龙的狂舞</title>
		<link>http://www.khotyn.com/2012/03/03/a_dance_with_dragons/</link>
		<comments>http://www.khotyn.com/2012/03/03/a_dance_with_dragons/#comments</comments>
		<pubDate>Sat, 03 Mar 2012 09:46:22 +0000</pubDate>
		<dc:creator>khotyn</dc:creator>
				<category><![CDATA[阅读笔记]]></category>

		<guid isPermaLink="false">http://www.khotyn.com/?p=797</guid>
		<description><![CDATA[
花了将近四个月的时间，终于将乔治・马丁的冰与火之歌的第五部《魔龙的狂舞》英文版啃完了，这大概是我迄今为止看过的最长的英文小说了，看完这部小说收获最大的地方应该就是对自己的英语阅读能力稍微有了一点信心，后面大概会持续地去看一些英文原版的著作。
]]></description>
			<content:encoded><![CDATA[<p><img src="http://farm8.staticflickr.com/7061/6948583061_1c50e4f8b8.jpg" alt="image" /></p>
<p>花了将近四个月的时间，终于将乔治・马丁的冰与火之歌的第五部《魔龙的狂舞》英文版啃完了，这大概是我迄今为止看过的最长的英文小说了，看完这部小说收获最大的地方应该就是对自己的英语阅读能力稍微有了一点信心，后面大概会持续地去看一些英文原版的著作。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.khotyn.com/2012/03/03/a_dance_with_dragons/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>美国丽人</title>
		<link>http://www.khotyn.com/2012/03/02/american_beauty/</link>
		<comments>http://www.khotyn.com/2012/03/02/american_beauty/#comments</comments>
		<pubDate>Fri, 02 Mar 2012 15:34:08 +0000</pubDate>
		<dc:creator>khotyn</dc:creator>
				<category><![CDATA[电影]]></category>

		<guid isPermaLink="false">http://www.khotyn.com/?p=792</guid>
		<description><![CDATA[
从来不知道自己想成为什么人，但是我一直努力避免成为一无所是的人
]]></description>
			<content:encoded><![CDATA[<p><img src="http://farm8.staticflickr.com/7187/6802473274_b9f31564c9_z.jpg" alt="美国丽人" /></p>
<p>从来不知道自己想成为什么人，但是我一直努力避免成为一无所是的人</p>
]]></content:encoded>
			<wfw:commentRss>http://www.khotyn.com/2012/03/02/american_beauty/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Nausicaa：一个把图片传到Flickr的命令行工具</title>
		<link>http://www.khotyn.com/2012/02/10/nausicaa/</link>
		<comments>http://www.khotyn.com/2012/02/10/nausicaa/#comments</comments>
		<pubDate>Thu, 09 Feb 2012 17:21:42 +0000</pubDate>
		<dc:creator>khotyn</dc:creator>
				<category><![CDATA[编程]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Shell]]></category>
		<category><![CDATA[Tool]]></category>

		<guid isPermaLink="false">http://www.khotyn.com/?p=786</guid>
		<description><![CDATA[懒惰是程序员的美德
前几天看了一片博客，灵感一现，发现平时发博客的时候，把图片传到图床上去要打开浏览器，再打开Flickr或者Yupoo，再上传照片，再找到照片对应的链接，然后这个链接才能够拿来用。看看吧，这个过程是多么的繁琐，作为一名把懒惰当成第一美德的程序员，我马上就想要折腾出一个命令行工具，来把图片上传到相应的图床，现在这个工具就是Nausicaa。
运行效果
那么，来看看上传的效果吧：

Nausicaa在你把图片上传之后，会把图片对应的各个尺寸的静态链接也返回回来，让你可以马上拿到图片的链接。
环境
要使用Nausicaa，最好在Unix-like系统下使用（Windows下谁会去用 [...]]]></description>
			<content:encoded><![CDATA[<h3>懒惰是程序员的美德</h3>
<p>前几天看了一片博客，灵感一现，发现平时发博客的时候，把图片传到图床上去要打开浏览器，再打开Flickr或者Yupoo，再上传照片，再找到照片对应的链接，然后这个链接才能够拿来用。看看吧，这个过程是多么的繁琐，作为一名把<strong>懒惰当成第一美德</strong>的程序员，我马上就想要折腾出一个命令行工具，来把图片上传到相应的图床，现在这个工具就是Nausicaa。</p>
<h3>运行效果</h3>
<p>那么，来看看上传的效果吧：</p>
<p><img src="https://a248.e.akamai.net/assets.github.com/img/b8f67a6baf4a762eda04490c0bdf222dfeec195a/687474703a2f2f6661726d382e737461746963666c69636b722e636f6d2f373139302f363834373138313339355f656663666364343963655f622e6a7067" alt="image" /></p>
<p>Nausicaa在你把图片上传之后，会把图片对应的各个尺寸的静态链接也返回回来，让你可以马上拿到图片的链接。</p>
<h3>环境</h3>
<p>要使用Nausicaa，最好在<strong>Unix-like系统</strong>下使用（Windows下谁会去用命令行？）。</p>
<p>另外Nausicaa还需要<strong>JRE 6或者以上的版本</strong>。</p>
<h3>下载与使用</h3>
<p>Nausicaa的下载地址是：<a href="https://github.com/downloads/khotyn/Nausicaa/nausicaa.jar">https://github.com/downloads/khotyn/Nausicaa/nausicaa.jar</a></p>
<p>使用说明，可以直接进项目主页看：<a href="https://github.com/khotyn/Nausicaa">https://github.com/khotyn/Nausicaa</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.khotyn.com/2012/02/10/nausicaa/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Java中Integer的大小是int的几倍</title>
		<link>http://www.khotyn.com/2012/02/02/size-ratio-of-integer-to-int/</link>
		<comments>http://www.khotyn.com/2012/02/02/size-ratio-of-integer-to-int/#comments</comments>
		<pubDate>Thu, 02 Feb 2012 15:55:10 +0000</pubDate>
		<dc:creator>khotyn</dc:creator>
				<category><![CDATA[JVM]]></category>
		<category><![CDATA[编程]]></category>
		<category><![CDATA[Java]]></category>

		<guid isPermaLink="false">http://www.khotyn.com/?p=782</guid>
		<description><![CDATA[今天看到一个不错的PPT：Build Memory-efficient Java Applications，开篇便提出了一个问题，在Hotspot JVM中，32位机器下，Integer对象的大小是int的几倍？
我们都知道在Java语言规范已经规定了int的大小是4个字节，那么Integer对象的大小是多少呢？要知道一个对象的大小，那么必须需要知道对象在虚拟机中的结构是怎样的，来看看Hotspot中对象在内存中的结构：

从上面的这张图里面可以看出，对象在内存中的结构主要包含以下几个部分：

Mark Word：对象的Mark  [...]]]></description>
			<content:encoded><![CDATA[<p>今天看到一个不错的<a href="http://domino.research.ibm.com/comm/research_people.nsf/pages/sevitsky.pubs.html/$FILE/oopsla08%20memory-efficient%20java%20slides.pdf">PPT：Build Memory-efficient Java Applications</a>，开篇便提出了一个问题，在Hotspot JVM中，32位机器下，Integer对象的大小是int的几倍？</p>
<p>我们都知道在Java语言规范已经规定了int的大小是4个字节，那么Integer对象的大小是多少呢？要知道一个对象的大小，那么必须需要知道对象在虚拟机中的结构是怎样的，来看看Hotspot中对象在内存中的结构：</p>
<p><img src="http://pic.yupoo.com/khotyn/BImBMDJy/wyn6n.png" alt="对象结构" /></p>
<p>从上面的这张图里面可以看出，对象在内存中的结构主要包含以下几个部分：</p>
<ul>
<li>Mark Word：对象的Mark Word部分占4个字节，其内容是一系列的标记位，比如轻量级锁的标记位，偏向锁标记位等等。</li>
<li>Class对象指针：Class对象指针的大小也是4个字节，其指向的位置是对象对应的Class对象（其对应的元数据对象）的内存地址</li>
<li>对象实际数据：这里面包括了对象的所有成员变量，其大小由各个成员变量的大小决定，比如：byte和boolean是1个字节，short和char是2个字节，int和float是4个字节，long和double是8个字节，reference是4个字节</li>
<li>对齐：最后一部分是对齐填充的字节，按8个字节填充。</li>
</ul>
<p>根据上面的图，那么我们可以得出Integer的对象的结构如下：</p>
<p><img src="http://pic.yupoo.com/khotyn/BImGBiSt/PPTTS.png" alt="Integer内存结构地址" /></p>
<p>Integer只有一个int类型的成员变量value，所以其对象实际数据部分的大小是4个字节，然后再在后面填充4个字节达到8字节的对齐，所以可以得出Integer对象的大小是16个字节。</p>
<p>因此，我们可以得出<strong>Integer对象的大小是原生的int类型的4倍</strong>。</p>
<p>关于对象的内存结构，需要注意数组的内存结构和普通对象的内存结构稍微不同，因为数据有一个长度length字段，所以在对象头后面还多了一个int类型的length字段，占4个字节，接下来才是数组中的数据，如下图：</p>
<p><img src="http://pic.yupoo.com/khotyn/BImK52BM/pAC9w.png" alt="数组对象内存结构" /></p>
<p>关于对象内存布局更多的内容，可以看这篇文章：<a href="http://www.codeinstructions.com/2008/12/java-objects-memory-structure.html">Java Objects Memory Structure</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.khotyn.com/2012/02/02/size-ratio-of-integer-to-int/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Varamyr – 让Nook 2也可以轻松阅读中文的epub</title>
		<link>http://www.khotyn.com/2012/01/12/varamyr/</link>
		<comments>http://www.khotyn.com/2012/01/12/varamyr/#comments</comments>
		<pubDate>Wed, 11 Jan 2012 16:01:00 +0000</pubDate>
		<dc:creator>khotyn</dc:creator>
				<category><![CDATA[Life]]></category>
		<category><![CDATA[编程]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Nook]]></category>
		<category><![CDATA[Tool]]></category>

		<guid isPermaLink="false">http://www.khotyn.com/?p=769</guid>
		<description><![CDATA[好啦，这个标题有点标题党的嫌疑，前几天入手了Nook 2，但是苦于Nook对中文支持并不好，看中文的epub直接显示方块或者问号之类的乱码。
网上看了下这个问题的大致解决方法有两个：一个是Root掉Nook；另一个往epub文件中塞入一段CSS，再在Nook中看的时候只需要选择Publisher  [...]]]></description>
			<content:encoded><![CDATA[<p>好啦，这个标题有点标题党的嫌疑，前几天<a href="http://blog.0xcafe.me/2012/01/06/nook-new-fisrt-look/">入手了Nook 2</a>，但是苦于Nook对中文支持并不好，看中文的epub直接显示方块或者问号之类的乱码。</p>
<p>网上看了下这个问题的大致解决方法有两个：一个是Root掉Nook；另一个往epub文件中塞入一段CSS，再在Nook中看的时候只需要选择<strong>Publisher Defaults</strong>就可以正常显示中文。</p>
<p>第一个方法风险太高，可能导致Nook变砖；</p>
<p>第二个方法的话可以用Calibre之类的工具来完成，但是Calibre这个东西本身太重了，每次打开关闭很耗时间，UI又丑，实在不想用。</p>
<p>所以，我需要一个命令行的工具来完成往epub中塞入一段CSS这个任务，这样可以和*nix下的其他工具结合起来使用，检测一个文件夹中如果新加入了epub文件，就直接进行转换，让整个过程完全自动化。现在这个命令行工具就是Varamyr（Varamyr是马丁大爷的冰与火之歌的第五部《魔龙的狂舞》序言里面的一个狼灵，打酱油的角色。）</p>
<h4>运行Varamyr你需要</h4>
<ol>
<li>JRE环境</li>
<li>*nix系统，不支持windows也不会支持windows</li>
<li>下载<a href="https://github.com/downloads/khotyn/Varamyr/varamyr.jar">varamyr.jar</a></li>
</ol>
<h4>如何使用？</h4>
<ol>
<li>运行命令：<code>java -jar varamyr.jar &lt;path-to-epub-file&gt;</code>，<code>&lt;path-to-epub-file&gt;</code>为你需要修改的epub文件的路径</li>
<li>看看在你修改的epub文件的路径下是不是多了一个类似<code>xxxx-varamyr.epub</code>的文件。</li>
</ol>
<h4>源代码 &amp; 原理</h4>
<ul>
<li>源代码放在github上了：<a href="https://github.com/khotyn/Varamyr">https://github.com/khotyn/Varamyr</a></li>
<li>原理很简单，不用讲了，直接看源代码吧。</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.khotyn.com/2012/01/12/varamyr/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Nook 2 入手记</title>
		<link>http://www.khotyn.com/2012/01/06/nook_2_first_glance/</link>
		<comments>http://www.khotyn.com/2012/01/06/nook_2_first_glance/#comments</comments>
		<pubDate>Fri, 06 Jan 2012 13:48:11 +0000</pubDate>
		<dc:creator>khotyn</dc:creator>
				<category><![CDATA[Life]]></category>
		<category><![CDATA[Nook]]></category>
		<category><![CDATA[生活]]></category>
		<category><![CDATA[随笔]]></category>

		<guid isPermaLink="false">http://www.khotyn.com/?p=765</guid>
		<description><![CDATA[经过了2个多月的挣扎，我终于了入手了一款电子书：Barnes &#38; Noble 出品的 Nook Simple Touch（即Nook 2），之所以选择Nook 2，是因为Kindle 3已经停产，现在价格比较高，Kindle  4和Kindle Touch的外观我实在是不喜欢，一股山寨味，于是在淘宝上找了一个店下单了Nook 2，前天晚上下单，昨天从深圳发货，今天早上就到手上了，快递非常迅速。

拿到手以后首先是外包装，白色，很小，右上角有一个THE ALL NEW  [...]]]></description>
			<content:encoded><![CDATA[<p>经过了2个多月的挣扎，我终于了入手了一款电子书：Barnes &amp; Noble 出品的 Nook Simple Touch（即Nook 2），之所以选择Nook 2，是因为Kindle 3已经停产，现在价格比较高，Kindle  4和Kindle Touch的外观我实在是不喜欢，一股山寨味，于是在淘宝上找了一个店下单了Nook 2，前天晚上下单，昨天从深圳发货，今天早上就到手上了，快递非常迅速。</p>
<p><img src="http://pic.yupoo.com/khotyn/BEeLcmon/medish.jpg" alt="image" /></p>
<p>拿到手以后首先是外包装，白色，很小，右上角有一个<code>THE ALL NEW NOOK</code>的字样，表示是全新的Nook，而不是官翻的机子。</p>
<p><img src="http://pic.yupoo.com/khotyn/BEeLmVAC/medish.jpg" alt="image" /></p>
<p>打开包装以后里面是就一只Nook和一个USB的连接线，没有其他配件了。首次使用需要充足够的电才能够开机。</p>
<p><img src="http://pic.yupoo.com/khotyn/BEeKLEpq/medish.jpg" alt="image" /></p>
<p>充电中，虽然屏幕上写着要等15分钟，但是实际上要差不多1个小时。等冲到了足够的电Nook会自己启动，然后就是一堆设置，连接上Wifi去激活Nook。</p>
<p><img src="http://pic.yupoo.com/khotyn/BEffJRRT/medish.jpg" alt="image" /></p>
<p>看看背面，Nook的开关键在背后，背面的中间是凹进去的，握起来比较舒服。</p>
<p>现在来看看Nook看书的效果到底如何吧：</p>
<p><img src="http://pic.yupoo.com/khotyn/BEeJR2az/medish.jpg" alt="image" /></p>
<p>这个是看英文的epub格式的电子书的照片，可以看到英文字体效果还是非常不错的。</p>
<p><img src="http://pic.yupoo.com/khotyn/BEfd9KAs/medish.jpg" alt="image" /></p>
<p>这张是看中文的epub格式的电子书，非常坑爹，直接显示方块了，Nook原生并不支持中文，需要用Root的方式去解决。</p>
<p><img src="http://pic.yupoo.com/khotyn/BEeK5IyI/medish.jpg" alt="image" /></p>
<p>然后是英文的pdf，可以看到Nook已经对pdf的文字进行了重新排列，以适合Nook的显示大小。</p>
<p><img src="http://pic.yupoo.com/khotyn/BEeQ0yXA/medish.jpg" alt="image" /></p>
<p>最后是中文的pdf，看起来效果也还可以。</p>
<p>另外再讲讲操作体验，Nook是红外线触摸屏的，触摸屏的体验非常不错，翻页非常灵敏，触摸屏用来查单词也是非常方便，只要点住单词即可，除了触摸屏以外，Nook在左右两边还提供了4个翻页键，但是遗憾的是按起来需要用点力，感觉不是很好。</p>
<p>屏幕的显示方面，效果还马马虎虎，因为Nook 2采用的是局部刷新，翻了6页以后才全刷，所以翻页后可以看到一些残影，这个非常让人不爽，不知道有没有什么办法可以解决这个问题。</p>
<p>至于和Kindle比较哪个好，哪个差，我也说不上来，总体来说，Nook 2还算是令人满意吧，如果你也要买一个电子书，不妨页考虑下Nook。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.khotyn.com/2012/01/06/nook_2_first_glance/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
	</channel>
</rss>

