月度归档:2013年10月

『批评中医』

『批评中医』我一直很钦佩方舟子在学术打假和科普工作上做的贡献,钦佩其在厚实的证据链支撑下给科学和事实一个有力的辩护。对于中医,我想说信奉中医的人们应该尝试着读完『批评中医』,不求改变态度,但求有新的认识。

中医是否是科学?所谓科学,它不分国界,不含民族、文化属性。意思是说,科学是全人类共同财富,没有一门科学学科是只有某个民族才有而其他民族不予接受的,也没有一门科学学科是只有某个文化背景的人才能理解而其他文化背景的人无法掌握的。所以,那些认为“西方科学界不承认中医是科学原因是不了解中国文化”的观点可以消停了。

在为“中医是科学”的辩护的观点中,有太多的概念偷换、以偏盖全在里面。比如一些中药材对特定疾病治疗有功效,这里面含有经验科学的成分,中医几千年发展下来,基本上是个试错的过程,“神农尝百草”就是这个过程的典型示范,但是这种获取经验的效率是低下的,并且有些疾病本身就是慢慢会自愈,只要中药不致死,都会被古人列入“有功效”的名单里,“幸存者偏差”问题的存在也说明效率只会比表面所见更加低下。千年的经验积累,只有几本谬误百出的药学著作。直至民国以前,中国的人均寿命都没有显著增加,这也从侧面说明了中医的作用寥寥。中医的理论基础是阴阳五行学说,这是一种朴素的唯物主义思想,只是一种与科学无关的哲学和玄学。

随着科普工作的展开,中医作为一种科学的研究会进入衰亡,这是一种趋势,中医的文化价值可能会代替它的科学价值渐渐成为主流。不久的将来,中医可能会出现在人文学科中,而非医学。

--EOF--

Xstream输出CDATA区段

在XML中,有些符号是有特殊含义的,比如<,&等,当解析器遇到这类字符时,就把它们按一定的语义解析了。于是,W3C定义了CDATA区段: CDATA区段里的文本不会被解析器解析。

用Xstream来将Java Bean转化为XML时,当Java Bean的String型成员变量中包含<, >, &, ', "等字符串,这些字符会被转义为&lt;, &gt;, &amp;, &apos;, &quot;。

如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class VM {
    private String sid = null;
 
    // getter & setter
}
 
public class TestVM {
    public void print() {
        System.out.println("TestVM");
    }
 
    public static void main(String[] args) {
        XStream xstream = new XStream(new XppDriver());
        xstream.alias("Result", VM.class);
        VM vm = new VM();
        vm.setSid("<>&'\"");
        System.out.println(xstream.toXML(vm));
    }
}

输出:

1
2
3
<Result>
  <sid>&lt;&gt;&amp;&apos;&quot;</sid>
</Result>

为了使Xstream正确处理这种含特殊字符的节点值,需要扩展XppDriver类,重写其中的createWriter()方法,指定成员变量名称(示例中的sid):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public class TestVM {
    public static void main(String[] args) {
        XStream xstream = new XStream(new XppDriver() {
            @Override
            public HierarchicalStreamWriter createWriter(Writer out) {
                return new PrettyPrintWriter(out) {
                    boolean cdata = false;
 
                    @Override
                    public void startNode(String name) {
                        super.startNode(name);
                        cdata = "sid".equals(name);
                    }
 
                    @Override
                    protected void writeText(QuickWriter writer, String text) {
                        if (cdata && !text.isEmpty()) {
                            writer.write("<![CDATA[");
                            writer.write(text);
                            writer.write("]]>");
                        } else {
                            super.writeText(writer, text);
                        }
                    }
                };
            }
        });
        xstream.alias("Result", VM.class);
        VM vm = new VM();
        vm.setSid("<>&'\"");
        System.out.println(xstream.toXML(vm));
    }
}

输出:

1
2
3
<Result>
  <sid><![CDATA[<>&'"]]></sid>
</Result>

--EOF--

ToStringBuilder工具类

一些meta类一般有很多成员变量,要把这些成员变量都打印出来,就需要覆盖toString()方法。重写toString()方法的工作量不小,而且是纯体力活,而且当meta类需要增减成员变量时还要修改toString()方法,以保持同步。后来使用Apache Commons Lang包里的ToStringBuilder工具类,用Java反射的方式一劳永逸解决toString()方法的覆盖问题。

1. 引入Maven依赖。

1
2
3
4
5
<dependency>
    <groupId>commons-lang</groupId>
    <artifactId>commons-lang</artifactId>
    <version>2.6</version>
</dependency>

2. 覆盖toString()方法。

1
2
3
4
5
6
7
8
9
10
11
12
public class VM {
    private String sid = null;
    private String status = null;
    private String fixip = null;
 
    //ignore getter/setter.
 
    public String toString() {
        return ToStringBuilder
                .reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);
    }
}

3. 测试

1
2
3
4
5
6
public class TestVM {
    public static void main(String[] args) {
        VM vm = new VM("5fc9ad01", "CREATING", "10.121.10.203");
        System.out.println(vm);
    }
}

打印输出:
VM[sid=5fc9ad01,status=CREATING,fixip=10.121.10.203]

输出样式可根据reflectionToString()的传入参数进行修改。以下ToStringStyle的不同取值对输出结果的影响:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
ToStringStyle.SHORT_PREFIX_STYLE:
VM[sid=5fc9ad01,status=CREATING,fixip=10.121.10.203]
 
ToStringStyle.DEFAULT_STYLE:
com.test.VM@2666e815[sid=5fc9ad01,status=CREATING,fixip=10.121.10.203]
 
ToStringStyle.MULTI_LINE_STYLE:
com.test.VM@4e106082[
  sid=5fc9ad01
  status=CREATING
  fixip=10.121.10.203
]
 
ToStringStyle.NO_FIELD_NAMES_STYLE:
com.test.VM@2666e815[5fc9ad01,CREATING,10.121.10.203]
 
ToStringStyle.SIMPLE_STYLE:
5fc9ad01,CREATING,10.121.10.203

另外,当变量被transient或者static限定词修饰时,ToStringBuilder.reflectionToString()方法不会输出这些变量。
--EOF--

『V字仇杀队』

V-for-Vendetta早在几年前,就听小蝌蚪说过这部电影,特别是里边经典的福克斯面具,意义深远。奇怪的是我一直拖着没看,直到近期才看完。

故事发生在英国,年月不详,彼时已形成一个由元首统治的极权社会,故事背景处处浮现着乔治·奥威尔笔下『1984』中的场景,老大哥、秘密警察、鬼话连篇的电视节目……政府为了彻底奴役民众的意志和躯体,一直在暗地研究某种致命病菌,将病毒投放在民众身上,同时又发放解药,自产自销。如此一来,统治者赢得了选票的同时,也在民众心中埋下了恐惧的种子,对政治恐惧是统治者最喜闻乐见的事情。某次病毒试验时,因为意外产生了一个变异者V,V在罗马数字中代表5,意味着是5号样本。V早先是个同性恋,这种反传统的行为在保守党眼里绝对是个异类,正因如此才被政府抓来进行病毒试验。最后V大难不死,逃脱试验场,浴火重生,成了一个复仇者,凭一己之力对抗整个极权社会。

V的目标很简单,完成400年前盖伊·福克斯的未尽事业,在11月5日这天,炸毁政府议会大厦。这意味着什么?用V的话来说,议会大厦只是个象征,炸毁它的行为也是个象征,象征本身没有意义,但是民众给予了象征具体的力量,只要有足够的人,炸毁议会大厦能够改变国家的局势。为了这次行动,V精心准备已久,分别从外部和内部动摇政府的根基,一方面,提前一年广播所有市民,公开自己的计划,成功的关键与否在于这一年他能否去除民众心中的恐惧,走上街头。另一方面,他对黑名单上的政府公众人物挨个复仇,不留情面,每一次复仇成功,除了引起内部人士的恐慌之外,还能增强民众对其的信任。这一年V所做的,就是布好一个局,最后推倒第一块多米诺骨牌,有了第一推动力,剩下的就是水到渠成的事情,即使他自己最终死去,也会有人帮其完成生前事业。星星之火,可以燎原。

从电影给人的启发来看,从内部进行分化是致使统治者倒台的第一推动力,比如剧中V策反政府二把手克里蒂,以及最后那个良知正义感尚存的警官的觉醒,他们之于极权瓦解的作用,就好像一列满载火药的火车之于议会大厦爆炸的作用。当然,民众敢于上街也是推翻极权统治的重要条件,所谓“人民不应该害怕他们的政府,政府应该害怕它的人民”,民众觉醒的意义在于,不会让不合理制度重复出现,不能让历史进程重蹈覆辙,否则,倒下去一个苏特勒,必然新起来一个克里蒂。

从电影剧情上看,『V字仇杀队』因为带点科幻和个人英雄主义色彩在内,与同是表现极权社会题材的『1984』、『浪潮』相比,无法像后者那样能使观众产生强烈的代入感,并且从整体上看,电影的说教味偏重。从演员的表现上看,从一而终带着面具出演的V(雨果·维文,『魔戒』中的精灵王)的表现无可挑剔,能感受到面具背后的愤怒和悲伤。至于娜塔莉·波特曼,那个时候的她显然还没有演『黑天鹅』时的娴熟技巧,多处表演令人出戏,表现中规中矩吧。

--EOF--