﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-keep moving! -文章分类-Groovy</title><link>http://www.blogjava.net/yangvlive/category/34239.html</link><description>Excellence in any department can be attained only by the labor of a lifetime; it is not to be purchased at a lesser price.</description><language>zh-cn</language><lastBuildDate>Sun, 31 Aug 2008 14:50:15 GMT</lastBuildDate><pubDate>Sun, 31 Aug 2008 14:50:15 GMT</pubDate><ttl>60</ttl><item><title>[转载] Groovy 1.5的新特性</title><link>http://www.blogjava.net/yangvlive/articles/225945.html</link><dc:creator>大石头</dc:creator><author>大石头</author><pubDate>Sun, 31 Aug 2008 13:00:00 GMT</pubDate><guid>http://www.blogjava.net/yangvlive/articles/225945.html</guid><wfw:comment>http://www.blogjava.net/yangvlive/comments/225945.html</wfw:comment><comments>http://www.blogjava.net/yangvlive/articles/225945.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yangvlive/comments/commentRss/225945.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yangvlive/services/trackbacks/225945.html</trackback:ping><description><![CDATA[<p><a href="http://groovy.codehaus.org/"><strong style="color: black; background-color: #ffff66"><u>作者 <strong>Guillaume Laforge</strong>译者 <strong>曹云飞</strong> 发布于 2008年1月15日 下午11时12分 <br />
<br />
Groovy</u></strong></a>，针对JVM的类Java动态语言，如陈年好酒一样成熟了。在2007年1月成功地发布了<strong style="color: black; background-color: #ffff66">Groovy</strong> 1.0之后，下一个主要的里程碑1.5版已经发布。在1.5版中有一些有趣而新颖的地方，我们会在这篇文章中考察这些特性。语言主要增强了对于Java 5特征的支持，包括注解、泛型和枚举，这使得<strong style="color: black; background-color: #ffff66">Groovy</strong>成为对于<strong>JVM完全支持的框架的唯一候选动态语言，框架包括Spring，Hibernate，JPA</strong>，Goole Guice或者TestNG。除了新的Java 5特性，<strong style="color: black; background-color: #ffff66">Groovy</strong>还在语言中增加了新的语法增强，以及更强大的动态特性定制，一个基于steroids的Swing UI构建器以及改进的工具支持。</p>
<div class="vendor-content-box-float">
<h3>相关<span class="vendor"><font size="2">厂商</font></span>内容</h3>
<p class="entrypdf"><a href="http://yangwei.javaeye.com/infoq/url.action?i=239&amp;t=f" target="_blank"><font color="#006600"><u>免费迷你书下载：深入浅出Struts 2 </u></font></a></p>
<p class="entrypdf"><a href="http://yangwei.javaeye.com/infoq/url.action?i=246&amp;t=f" target="_blank"><font color="#006600"><u>活动：体验基于OpenSolaris的Web/企业应用（8.30 杭州） </u></font></a></p>
<p class="entrypdf"><a href="http://yangwei.javaeye.com/infoq/url.action?i=241&amp;t=f" target="_blank"><font color="#006600"><u>SOY Framework：Java富客户端快速开发框架 </u></font></a></p>
<p class="entryarticle"><a href="http://yangwei.javaeye.com/infoq/url.action?i=242&amp;t=f" target="_blank"><font color="#006600"><u>Hadoop中的集群配置和使用技巧 </u></font></a></p>
<p class="entrypdf"><a href="http://yangwei.javaeye.com/infoq/url.action?i=243&amp;t=f" target="_blank"><u><font color="#006600">免费迷你书下载：Grails入门指南 </font></u></a></p>
<h3>相关赞助商</h3>
<div class="entrysponsors"><a href="http://yangwei.javaeye.com/infoq/url.action?i=244&amp;t=f" target="_blank"><u><font color="#006600">InfoQ中文站Java社区</font></u></a>，关注企业Java社区的变化与创新，通过新闻、文章、视频访谈和演讲以及迷你书等为中国Java技术社区提供一流资讯。 </div>
</div>
<h2>为什么一个更加<strong style="color: black; background-color: #ffff66">groovy</strong>的<strong style="color: black; background-color: #ffff66">Groovy</strong>是很重要的</h2>
<p><strong style="color: black; background-color: #ffff66">Groovy</strong>的关键卖点始终是它<strong>与Java的无缝集成</strong>。你能够很容易地把<strong style="color: black; background-color: #ffff66">Groovy</strong>和Java的类混合搭配：你可以让一个Java类实现一个<strong style="color: black; background-color: #ffff66">Groovy</strong>接口，然后让一个<strong style="color: black; background-color: #ffff66">Groovy</strong>类继承那个Java类，或者相反。不幸的是，绝大多数其他的候选的JVM语言不能让你无缝的在两种不同的语言之间交换类。因此，如果你希望为工作使用最好的语言而不放弃优美的类的层次结构，你没有太多的选择，而<strong style="color: black; background-color: #ffff66">Groovy</strong>使得你可以自由的将两种语言以几乎透明的方式集成在一起。</p>
<p><strong style="color: black; background-color: #ffff66">Groovy</strong>与Java共享同样的库，同样的对象模型，同样的线程模型，同样的安全模型。在某种意义上，你可以认为<strong style="color: black; background-color: #ffff66">Groovy</strong>是你的Java项目的一个实现细节，<strong>而不必忍受阻抗失配问题</strong>。</p>
<p><strong style="color: black; background-color: #ffff66">Groovy</strong>就是Java，而且<strong style="color: black; background-color: #ffff66">Groovy</strong>使得Java更<strong style="color: black; background-color: #ffff66">groovy</strong>了。与其他语言相比，<strong style="color: black; background-color: #ffff66">Groovy</strong>对于Java开发者无疑提供了最平滑的学习曲线，这得益于两者非常相似的语法。</p>
<p>需要牢记的是<strong style="color: black; background-color: #ffff66">Groovy</strong>产生的是正常的Java字节码而且使用普通的JDK库，所以你不需要学习全部的新的API而且不需要复杂的集成机制：极其方便，<strong style="color: black; background-color: #ffff66">Groovy</strong>和Java是可以相互交换的。附加的好处是你可以<strong>保护对你的Java开发人员Java技巧方面的投资，或者是昂贵的应用服务器</strong>，或者第三方的或者<strong>公司自己开发的库</strong>，你可以在<strong style="color: black; background-color: #ffff66">Groovy</strong>中毫无问题地重用他们。</p>
<p>其他不支持强类型的候选语言，在调用JDK、第三方库或者公司自己的库的时候，由于它们不能辨别同一方法的某一多态变种，所以始终不能调用所有的Java方法。当你选择一种语言来提高你的生产率或者使你的代码可读性更强的时候，如果你需要调用其他Java类，你必须非常谨慎的选择语言，因为可能会碰到很多麻烦。</p>
<p>今天，所有主要的企业框架都需要使用注解、枚举或者泛型这样的语言特性来充分提高它们的效率。幸运的是，开发者使用<strong style="color: black; background-color: #ffff66">Groovy</strong>1.5的话就可以在他们的项目中使用所有的Java 5特性并因此而获益。让我们看看在<strong style="color: black; background-color: #ffff66">Groovy</strong>中如何使用注解，枚举和泛型。</p>
<h2>Java 5增加的部分<br />
</h2>
<p><strong style="color: black; background-color: #ffff66">Groovy</strong>编译器始终产生与以前的Java VM兼容的Java字节码，但是由于<strong style="color: black; background-color: #ffff66">Groovy</strong>使用了JDK1.4的核心库，所以<strong style="color: black; background-color: #ffff66">Groovy</strong>依赖于JDK1.4。然而，对于这些Java 5中增加的部分，肯定需要使用Java 5的字节码。例如，产生的类中也许包含代表着运行时保留策略注解的字节码信息。所以，虽然<strong style="color: black; background-color: #ffff66">Groovy</strong>1.5能够在JDK1.4上运行，但是某些<strong style="color: black; background-color: #ffff66">Groovy</strong>的特征只能在JDK1.5上使用 —— 出现这种情况时，本文会作出声明。</p>
<h3>可变的参数<br />
</h3>
<p>在Java 5中创建了省略号表示法，代表方法的参数是可变长度的。通过三个小圆点，Java允许用户在一个方法的末端输入相同类型的任意数量的参数 —— 实际上，可变长度参数（vararg）就是一个那种类型的元素的数组。可变长度参数在<strong style="color: black; background-color: #ffff66">Groovy</strong> 1.0中已经出现了 —— 现在仍然可以在JDK1.4运行时环境下工作，1.0足以向你展示如何来使用他们了。基本上，只要当一个方法的最后一个参数是一个对象数组，或者是一个有三个点的参数，你就可以向这个方法传入多重参数。</p>
<p>第一个例子介绍了在<strong style="color: black; background-color: #ffff66">Groovy</strong>中用省略号来使用可变长度变量的方法：</p>
<pre><strong>int</strong> sum(int... someInts) {
<strong><a name="baidusnap1"></a><strong style="color: black; background-color: #a0ffff">def</strong></strong> total = 0
<strong>for</strong> (int i = 0; i &lt; someInts.size(); i++)
total += someInts[i]
<strong>return</strong> total
}
<strong>assert</strong> sum(1)       == 1
<strong>assert</strong> sum(1, 2)    == 3
<strong>assert</strong> sum(1, 2, 3) == 6</pre>
<p>这个例子中所用的断言显示了我们如何传入任意多的int类型的参数。还有一个有趣的地方，为了更好的兼容Java语法，Java中经典的循环方式也加入了<strong style="color: black; background-color: #ffff66">Groovy</strong>中 —— 尽管在<strong style="color: black; background-color: #ffff66">groovy</strong>中更有<strong style="color: black; background-color: #ffff66">groovy</strong>特色的循环是用in关键字，同样可以透明地遍历各种各样的数组或者集合类型。</p>
<p>请注意使用一个数组作为最后一个参数同样可以支持可变长度变量，就像下面这样声明方法：</p>
<pre>int sum(int[] someInts) { /* */ }</pre>
<p>这个代码片断是非常无聊的。很明显有很多更有表现力的方式来计算一个总和。例如，如果你有一个数字的列表，你可以在一行代码中计算他们的总和：</p>
<pre><strong>assert</strong> [1, 2, 3].sum() == 6</pre>
<p>在<strong style="color: black; background-color: #ffff66">Groovy</strong>中可变长度变量不需要JDK 5作为基本的Java运行时环境，在下面的章节中我们要介绍的注解则需要JDK 5。</p>
<h3>注解<br />
</h3>
<p>正如在JBoss Seam的文档中所介绍的那样，Seam支持使用<strong style="color: black; background-color: #ffff66">Groovy</strong>来写Seam的实体，控制器和组件，类似<strong>@Entity，@Id，@Override</strong>以及其他的注解可以用来修饰你的bean：</p>
<pre>@Entity
@Name("hotel")
<strong>class</strong> Hotel <strong>implements</strong> Serializable
{
@Id @GeneratedValue
Long id
@Length(max=50) @NotNull
String name
@Length(max=100) @NotNull
String address
@Length(max=40) @NotNull
String city
@Length(min=2, max=10) @NotNull
String state
@Length(min=4, max=6) @NotNull
String zip
@Length(min=2, max=40) @NotNull
String country
@Column(precision=6, scale=2)
BigDecimal price
@Override
String toString() {
<strong>return</strong> "Hotel(${name}, ${address}, ${city}, ${zip})"
}
}</pre>
<p>Hotel实体用@Entity注解来标识，用@Name给了它一个名字。可以向你的注解传递不同的参数，例如在@Length注解约束中，为了做有效性检查可以给注解设置不同的上界和下界。在实例中你还会注意到<strong><strong style="color: black; background-color: #ffff66">Groovy</strong>的属性</strong>：getter方法和setter方法都到哪里去了？公有或者私有的修饰符在哪里？你不必等待Java 7或者Java 8来获得属性！在<strong style="color: black; background-color: #ffff66">Groovy</strong>中，按照惯例，定义一个属性非常简单：String country：这样就会自动生成一个私有的country成员变量，同时生成一个公有的getter和setter方法。<strong>你的代码自然而然的变得简洁而易读</strong>。</p>
<p>在<strong style="color: black; background-color: #ffff66">Groovy</strong>中，注解可以象在Java中一样用在类、成员变量、方法和方法参数上。但是，有两个很容易犯错误的地方需要小心。第一，你可以在<strong style="color: black; background-color: #ffff66">Groovy</strong>中用注解，可是你不能定义它们 —— 然而，在一个快要到来的<strong style="color: black; background-color: #ffff66">Groovy</strong>版本中将可以定义注解。第二，虽然<strong style="color: black; background-color: #ffff66">Groovy</strong>的语法几乎与Java的语法100%相同，但是在注解中传入一个数组作为参数时还是有一点点不同：<strong style="color: black; background-color: #ffff66">Groovy</strong>不是用圆括号来括起元素，而是需要使用方括号，目的是为了提供更一致的语法 —— 在<strong style="color: black; background-color: #ffff66">Groovy</strong>中列表和数组都用方括号来括起他们的元素。</p>
<p>通过<strong style="color: black; background-color: #ffff66">Groovy</strong>1.5中的注解，你可以在<strong style="color: black; background-color: #ffff66">Groovy</strong>中方便地为JPA或者Hibernate定义你的的带注解的bean</p>
<p class="href-wide">（<a href="http://www.curious-creature.org/2007/03/25/persistence-made-easy-with-groovy-and-jpa/"><u><font color="#006600">http://www.curious-creature.org/2007/03/25/persistence-made-easy-with-</font><strong style="color: black; background-color: #ffff66">groovy</strong><font color="#006600">-and-jpa/</font></u></a>），在你的Spring服务上增加一个<big><span style="font-size: medium">@Transactional</span></big> 注解，使用TestNG和Fest来测试你的Swing UI（<a href="http://www.jroller.com/aalmiray/entry/testing_groovy_uis_with_fest"><u><font color="#006600">http://www.jroller.com/aalmiray/entry/testing_</font><strong style="color: black; background-color: #ffff66">groovy</strong><font color="#006600">_uis_with_fest</font></u></a>）。在<strong style="color: black; background-color: #ffff66">Groovy</strong>项目中你可以使用所有支持注解的有用而强大的企业框架。</p>
<h3>枚举</h3>
<p>当你需要一组固定数量的相同类型的常量时，枚举是很方便的。例如你需要一种干净的方式来为日期定义常量而不借助使用整数常量，那么枚举是你的好帮手。下面的片断显示了如何定义一星期中的日子：</p>
<pre><strong>enum</strong> Day {
SUNDAY, MONDAY, TUESDAY, WEDNESDAY,
THURSDAY, FRIDAY, SATURDAY
}</pre>
<p>一旦你定义了你的枚举，你可以在Java中以通常的记法<strong>Day.MONDAY</strong>来使用它，还可以使用枚举来润色你的switch/case语句：</p>
<pre><strong><strong style="color: black; background-color: #a0ffff">def</strong></strong> today = Day.SATURDAY
<strong>switch</strong> (today) {
// Saturday or Sunday
<strong>case</strong> [Day.SATURDAY, Day.SUNDAY]:
println "Weekends are cool"
<strong>break</strong>
// a day between Monday and Friday
<strong>case</strong> Day.MONDAY..Day.FRIDAY:
println "Boring work day"
<strong>break</strong>
<strong>default</strong>:
println "Are you sure this is a valid day?"
}</pre>
<p>请注意<strong style="color: black; background-color: #ffff66">Groovy</strong>的switch语句比类似C风格语言的switch语句要强大一些，在<strong style="color: black; background-color: #ffff66">Groovy</strong>中可以在switch和case语句使用任何类型的对象。不用为每一个枚举值罗列七个不同的case语句块，你可以在列表或者ranges（<strong style="color: black; background-color: #ffff66">Groovy</strong>集合类的一种类型）中重新分组case语句：当值出现在列表或者range中，case将为真而且会执行它关联的命令。</p>
<p>受到Java教程的启示，这里是一个更复杂的关于天文学的例子，向你展示了在枚举中如何包含属性，构造器和方法：</p>
<pre><strong>enum</strong> Planet {
MERCURY (3.303e+23, 2.4397e6),
VENUS   (4.869e+24, 6.0518e6),
EARTH   (5.976e+24, 6.37814e6),
MARS    (6.421e+23, 3.3972e6),
JUPITER (1.9e+27,   7.1492e7),
SATURN  (5.688e+26, 6.0268e7),
URANUS  (8.686e+25, 2.5559e7),
NEPTUNE (1.024e+26, 2.4746e7)
<strong>double</strong> mass
<strong>double</strong> radius
Planet(<strong>double</strong> mass, <strong>double</strong> radius) {
<strong>this</strong>.mass = mass;
<strong>this</strong>.radius = radius;
}
<strong>void</strong> printMe() {
println "${name()} has a mass of ${mass} " +
"and a radius of ${radius}"
}
}
Planet.EARTH.printMe()</pre>
<p>与注解一样，由于产生了Java 5的字节码，<strong style="color: black; background-color: #ffff66">Groovy</strong>中的枚举需要JDK 5+的环境才能运行，</p>
<h3>静态导入<br />
</h3>
<p>在前面关于枚举的例子中，我们始终需要在枚举值的前面加上它的父枚举类，但是通过静态导入（可以在JDK1.4运行时环境上工作）我们可以去掉Planet前缀，从而节省一些字符。</p>
<pre><strong>import static</strong> Planet.*
SATURN.printMe()</pre>
<p>这样就不再需要Planet前缀。当然，静态导入不仅仅对枚举有效，对其他类和静态成员变量同样有效。我们不妨作些数学计算。</p>
<pre><strong>import static</strong> java.lang.Math.*
<strong>assert</strong> sin(PI / 6) + cos(PI / 3) == 1</pre>
<p>java.lang.Math的静态方法和静态常量都被静态导入了，这样使得表达式更加简明。但是如果sine和cosine的缩写不便于你阅读，那么你可以使用<strong style="color: black; background-color: #ffff66">Groovy</strong>中的<a name="baidusnap2"></a><strong style="color: black; background-color: #99ff99">as</strong>关键字来做别名：</p>
<pre><strong>import static</strong> java.lang.Math.PI
<strong>import static</strong> java.lang.Math.sin <strong style="color: black; background-color: #99ff99">as</strong> sine
<strong>import static</strong> java.lang.Math.cos <strong style="color: black; background-color: #99ff99">as</strong> cosine
<strong>assert</strong> sine(PI / 6) + cosine(PI / 3) == 1</pre>
<p>别名不仅仅用于静态导入，也可以用于正常的导入，是很有用的方法。例如在很多框架中有名字非常长的类，可以使用别名来增加快捷记法，或者重命名名字不太直观的方法或者常量，或者重命名与你的命名约定标准不一致的方法或常量。</p>
<h3>泛型</h3>
<p>在Java 5中有争议的特性：泛型，也出现在<strong style="color: black; background-color: #ffff66">Groovy</strong> 1.5的最新版本中。毕竟，开始的时候可能觉得在一个动态语言中加入更多类型信息是多余的。Java开发人员通常相信因为类型擦除（为了向后兼容Java以前的版本）使得在类的字节码中没有保留代表泛型的类型信息。然而，这是错误的看法，通过反射API，你可以内省一个类从而发现它的成员变量类型或者它的有泛型详细信息的方法参数类型。<br />
</p>
<p>例如，当你声明了类型为<strong>List</strong>的成员变量时，这个信息是在字节码的某个地方以某种元信息的方式保存的，尽管这个成员变量确实仅仅是<strong>List</strong>类型的。这种反射信息被诸如JPA或者Hibernate这样的企业框架所使用，将一个元素的集合中的实体关联到代表这些元素的类型的实体。<br />
为了实践这些理论，让我们检查泛型信息是否保存在类的成员变量中。</p>
<pre><strong>class</strong> Talk {
String title
}
<strong>class</strong> Speaker {
String name
List talks = []
}
<strong><strong style="color: black; background-color: #a0ffff">def</strong></strong> me = new Speaker(
name: 'Guillaume Laforge',
talks: [
<strong>new</strong> Talk(title: '<strong style="color: black; background-color: #ffff66">Groovy</strong>'),
<strong>new</strong> Talk(title: 'Grails')
])
<strong><strong style="color: black; background-color: #a0ffff">def</strong></strong> talksField =  me.class.getDeclaredField('talks')
<strong>assert</strong> talksField.genericType.toString() ==
&nbsp;'java.util.Listt'</pre>
<p>我们定义了两个类：一个在会议上给出Talk的Speaker类。在Speaker类中，talks属性的类型是<strong>List</strong>。然后，我们创建了一个Speaker实例，用两个优美的捷径来初始化name和talks属性，并创建了一个Talk实例的列表。当初始化代码就绪后，我们取得代表talks的成员变量，然后检查泛型信息是否正确：正确！<strong>talks</strong>是一个<strong>List</strong>，但是它是一个<strong>Talk</strong>的<strong>List</strong>。</p>
<h3>共变的返回类型<br />
</h3>
<p>在Java 5中，如果你在一个子类中有一个方法，其名称与参数类型与父类中的方法相同，但是返回值是父类方法的返回值的子类，那么我们可以覆盖父类的方法。在<strong style="color: black; background-color: #ffff66">Groovy</strong>1.0中，不支持共变的返回类型。但是在<strong style="color: black; background-color: #ffff66">Groovy</strong>1.5中，你可以使用共变返回类型。而且，如果你试图覆盖一个方法而返回类型不是父类方法的返回类型的子类，将抛出一个编译错误。共变的返回类型对于参数化的类型同样有效。</p>
<p>除了因为支持Java 5的特性而给<strong style="color: black; background-color: #ffff66">Groovy</strong>语言带来了一些增强外，<strong style="color: black; background-color: #ffff66">Groovy</strong>1.5还引入了其他一些语法的增强，我们在下面的章节中会探索这些部分。</p>
<h2>增加的语法</h2>
<h3>Elvis操作符<br />
</h3>
<p>Java 5的特性除了带给<strong style="color: black; background-color: #ffff66">Groovy</strong>注解，泛型和枚举，还增加了一个新操作符—— ?:，Elivis操作符。当你看这个操作符的时候，你很容易猜测为什么会这样命名 —— 如果不是，可以根据Smiley来思考。这个新操作符实际上是一个三目操作符的便捷记法。你是否经常使用三目操作符来改变一个变量的值？如果它是null那么给它分配一个缺省值。在Java中典型的情况是这样的：</p>
<pre>String name = <span style="color: #ff0000">"Guillaume"</span>;
String displayName = name != <strong>null</strong> ? name : <span style="color: #ff0000">"Unknown";</span></pre>
<p>在<strong style="color: black; background-color: #ffff66">Groovy</strong>中，由于语言本身可以按需&#8220;强制&#8221;类型转换到布尔值（例如在if或者while构造中条件表达式需要为布尔值），在这个语句中，我们可以忽略和null的比较，因为当一个String是null的时候，它被强制转换为false，所以在<strong style="color: black; background-color: #ffff66">Groovy</strong>中语句会变为：</p>
<pre>String name = <span style="color: #ff0000">"Guillaume"</span>
String displayName = name ? name : <span style="color: #ff0000">"Unknown"</span></pre>
<p>然而，你仍然会注意到name变量的重复，这破坏了DRY原则（不要重复你自己 Don't Repeat Yourself）。由于这个构造非常普遍，所以引入了Elvis操作符来简化这些重复的现象，语句变成：</p>
<pre>String name = <span style="color: #ff0000">"Guillaume"</span>
String displayName = name ?: <span style="color: #ff0000">"Unknown"</span></pre>
<p>name变量的第二次出现被简单的忽略了，三目操作符不再是三目的了，缩短为这种更简明的形式。</p>
<p>还有一点值得注意的是这个新的构造没有副作用，由于第一个元素（这里是name）不会象在三目操作符中那样被估值两次，所以不需要引入一个中间的临时变量来保持三目操作符中第一个元素的第一次估值。</p>
<h3>经典的循环<br />
</h3>
<p>虽然<strong style="color: black; background-color: #ffff66">Groovy</strong>严格地来说不是100％的Java的超集，但是在每一个<strong style="color: black; background-color: #ffff66">Groovy</strong>的新版本中，其语法都更接近Java的语法，在<strong style="color: black; background-color: #ffff66">Groovy</strong>中越来越多的Java代码是有效的。这种兼容性的好处是当你开始用<strong style="color: black; background-color: #ffff66">Groovy</strong>工作时，你可以拷贝并粘贴Java代码到你的<strong style="color: black; background-color: #ffff66">Groovy</strong>类中，它们会如你所愿地工作。然后，随着时间的推移你学习了<strong style="color: black; background-color: #ffff66">Groovy</strong>语言，你可以扔掉那些从Java拷贝来的在<strong style="color: black; background-color: #ffff66">Groovy</strong>中不地道的代码，使用GStrings（内插字符串），或者闭包等等。<strong style="color: black; background-color: #ffff66">Groovy</strong>为Java开发者提供了一个非常平滑的学习曲线。</p>
<p>然而，<strong style="color: black; background-color: #ffff66">Groovy</strong>中有一处忽略了Java语法的兼容性，实际上<strong style="color: black; background-color: #ffff66">Groovy</strong>中不允许使用从Java语言的C背景继承而来的经典的循环语法。最初，<strong style="color: black; background-color: #ffff66">Groovy</strong>开发者认为经典的循环语法不是最好的，他们更喜欢使用可读性更好的for/in构造。但是由于<strong style="color: black; background-color: #ffff66">Groovy</strong>用户经常要求<strong style="color: black; background-color: #ffff66">Groovy</strong>包含这个旧的循环构造，所以<strong style="color: black; background-color: #ffff66">Groovy</strong>团队决定支持它。</p>
<p>在<strong style="color: black; background-color: #ffff66">Groovy</strong> 1.5中，你可以选择<strong style="color: black; background-color: #ffff66">Groovy</strong>的for/in构造，或者经典的for循环构造：</p>
<pre><strong>for</strong> (i <strong>in</strong> 0..9)
println i
<strong>for</strong> (<strong>int</strong> i = 0; i &lt; 10; i++)
println i</pre>
<p>最终，这也许只是品味不同，<strong style="color: black; background-color: #ffff66">Groovy</strong>的熟手用户通常更喜欢for/in循环这样更加简明的语法。</p>
<h3>没有圆括号的命名参数<br />
</h3>
<p>由于易适应且简明的语法，以及高级的动态能力，<strong><strong style="color: black; background-color: #ffff66">Groovy</strong>是实现内部</strong><strong>领域特定语言</strong><strong>（Domain-Specific Languages）的理想选择</strong>。当你希望在业务问题专家和开发者之间共享一种公共的比喻说法的时候，你可以借<strong style="color: black; background-color: #ffff66">Groovy</strong>之力来创建一个专用的商业语言，用该语言为你的应用的关键概念和商业规则建模。这些DSL的一个重要方面是使得代码非常可读，而且让非技术人员更容易写代码。为了更进一步实现这个目标，<strong style="color: black; background-color: #ffff66">Groovy</strong>的语法做了通融，允许我们使用没有圆括号括起来的命名参数。</p>
<p>首先，在<strong style="color: black; background-color: #ffff66">Groovy</strong>中命名参数看起来是这样的：</p>
<pre>fund.compare(to: benchmarkFund, in: euros)
compare(fund: someFund, to: benchmark, in: euros)</pre>
<p>通过向数字加入新的属性 —— 这在<strong style="color: black; background-color: #ffff66">Groovy</strong>中是可能的，但是超出了这篇文章的范围 —— 我们可以写出像这样的代码：</p>
<pre>monster.move(left: 3.meters, at: 5.mph)</pre>
<p>现在通过忽略圆括号，代码变得更清晰了：</p>
<pre>fund.compare to: benchmarkFund, in: euros
compare fund: someFund, to: benchmark, in: euros
monster.move left: 3.meters, at: 5.mph</pre>
<p>显然，这没有很大的区别，但是每个语句变得更接近浅白的英语句子，而且在宿主语言中删除了通常冗余的技术代码。<strong style="color: black; background-color: #ffff66">Groovy</strong>语言这个小小的增强给予了商业DSL设计人员更多的选择。</p>
<h2>改善的工具支持<br />
</h2>
<p>当<strong style="color: black; background-color: #ffff66">Groovy</strong>还不成熟的时候，一个常见的弱点是缺乏好的工具支持：工具系列和IDE支持都不到位。幸运的是，随着<strong style="color: black; background-color: #ffff66">Groovy</strong>和Grails web框架的成熟和成功，这种状况得到了改变。</p>
<h2>&#8220;联合&#8221;编译器的介绍<br />
</h2>
<p><strong style="color: black; background-color: #ffff66">Groovy</strong>以它与Java的透明而且无缝的集成而闻名。但是这不仅仅意味着在<strong style="color: black; background-color: #ffff66">Groovy</strong>脚本中可以调用Java方法，不，两个语言之间的集成远不止于此。例如，一个<strong style="color: black; background-color: #ffff66">Groovy</strong>类继承一个Java类，而该Java类实现一个<strong style="color: black; background-color: #ffff66">Groovy</strong>接口是完全可能的，反之亦然。不幸的是，其他候选语言不支持这样做。然而，到目前为止，当把<strong style="color: black; background-color: #ffff66">Groovy</strong>和Java混合起来使用的时候，你在编译时要小心选择正确的编译顺序，如果两个语言中出现循环依赖，那么你也许会碰到一个&#8220;鸡与蛋&#8221;的问题。幸运的是在<strong style="color: black; background-color: #ffff66">Groovy</strong> 1.5中这不再是问题，谢谢获奖的<a href="http://www.jetbrains/idea/"><u><font color="#006600">Java IDE IntelliJ IDEA</font></u></a>的创建者JetBrains的一个贡献，你可以使用一个&#8220;联合&#8221;编译器将<strong style="color: black; background-color: #ffff66">Groovy</strong>和Java代码放在一起一次编译而不必考虑类之间的依赖关系。</p>
<p>如果你希望在命令行使用联合编译器，你可以像通常那样调用groovyc命令，但是使用-j参数来进行联合编译：</p>
<pre>groovyc *.<strong style="color: black; background-color: #ffff66">groovy</strong> *.java -j -Jsource=1.4 -Jtarget=1.4</pre>
<p>为了向基本的javac命令传递参数，你可以用J作为参数的前缀。你还可以在你的Ant或者Maven构建文件中使用联合编译器执行Ant任务：</p>
<pre>&lt;taskdef name="groovyc"
classname="org.codehaus.<strong style="color: black; background-color: #ffff66">groovy</strong>.ant.Groovyc"
classpathref="my.classpath"/&gt;
&lt;groovyc
srcdir="${mainSourceDirectory}"
destdir="${mainClassesDirectory}"
classpathref="my.classpath"
jointCompilationOptions="-j -Jsource=1.4 -Jtarget=1.4" /&gt;</pre>
<h3><strong style="color: black; background-color: #ffff66">Groovy</strong>的Maven插件<br />
</h3>
<p>对于Maven用户，在Codehaus有一个全特性的Maven插件项目允许你构建自己的Java/<strong style="color: black; background-color: #ffff66">Groovy</strong>应用：编译你的<strong style="color: black; background-color: #ffff66">Groovy</strong>和Java代码，从JavaDoc标签生成文档，甚至允许你在<strong style="color: black; background-color: #ffff66">Groovy</strong>中开发自己的Maven插件。还有一个Maven的原型可以更迅速的引导你的<strong style="color: black; background-color: #ffff66">Groovy</strong>项目。要得到更多信息，你可以参考插件的文档：<a href="http://mojo.codehaus.org/groovy/index.html"><u><font color="#006600">http://mojo.codehaus.org/</font><strong style="color: black; background-color: #ffff66">groovy</strong><font color="#006600">/index.html</font></u></a></p>
<h3>GroovyDoc文档工具<br />
</h3>
<p>作为一个Java开发人员，你习惯于通过你的类，接口，成员变量或者方法的注释中的JavaDoc标签来生成代码文档。在<strong style="color: black; background-color: #ffff66">Groovy</strong>中，你仍然可以在你的注释中使用这样的标签，使用一个叫做GroovyDoc的工具为你所有的<strong style="color: black; background-color: #ffff66">Groovy</strong>类生成与JavaDoc同样的文档。</p>
<p>这里有一个Ant任务，你可以定义并用它来产生文档：</p>
<pre>&lt;taskdef name="groovydoc"
classname="org.codehaus.<strong style="color: black; background-color: #ffff66">groovy</strong>.ant.Groovydoc"&gt;
&lt;classpath&gt;
&lt;path path="${mainClassesDirectory}"/&gt;
&lt;path refid="compilePath"/&gt;
&lt;/classpath&gt;
&lt;/taskdef&gt;
&lt;groovydoc
destdir="${docsDirectory}/gapi"
sourcepath="${mainSourceDirectory}"
packagenames="**.*" use="true"
windowtitle="Groovydoc" private="false"/&gt;</pre>
<h2>新的交互性shell和Swing控制台<br />
</h2>
<p><strong style="color: black; background-color: #ffff66">Groovy</strong>的发行版本总是包含两个不同的shell：一个命令行shell和一个Swing控制台。命令行shell，Groovysh，就其与用户的交互性而言从来都不是很友好：当你希望执行一个语句的时候，你不得不在每个语句后面键入&#8220;go&#8221;或者&#8220;execute&#8221;，这样才能执行。为了某些快速的原型开发或者试用一些新的API，每次都键入&#8220;go&#8221;是非常累赘的。在<strong style="color: black; background-color: #ffff66">Groovy</strong> 1.5中情况变化了，有了新的交互式的shell。不再需要键入&#8220;go&#8221;。</p>
<p>这个新的shell有几个增强的特性，例如使用了提供ANSI着色的JLine库，tab命令补全，行编辑能力。你可以与不同的脚本缓冲器工作，记住已经导入的类，装载现存的脚本，将当前脚本保存到一个文件中，浏览历史记录，等等。欲得到shell所支持特性的更详细解释，请参阅<a href="http://groovy.codehaus.org/Groovy+Shel"><u><font color="#006600">文档</font></u></a>。</p>
<p>不仅仅命令行shell得到了提高，Swing控制台也有改进，有了新的工具条，先进的undo能力，可以增大或者缩小字体，语法高亮等，总之，控制台有了很多提高。</p>
<h3>IntelliJ IDEA JetGroovy 插件<br />
</h3>
<p>JetGroovy插件是最棒的工具支持：一个免费而且开源的专用于支持<strong style="color: black; background-color: #ffff66">Groovy</strong>和Grails的IntelliJ IDEA插件。这个插件是由JetBrains他们自己开发的，对于语言和Web框架都提供了无以伦比的支持。</p>
<p>插件对<strong style="color: black; background-color: #ffff66">Groovy</strong>有专门的支持，其中部分特性：</p>
<ul>
    <li>对于所有的语法都可以<strong>语法高亮</strong>，对于未识别的类型加不同的警告。<br />
    <li>可以<strong>运行<strong style="color: black; background-color: #ffff66">Groovy</strong>类，脚本和用<strong style="color: black; background-color: #ffff66">Groovy</strong>写的JUnit测试用例。</strong><br />
    <li><strong>调试器</strong>：你可以一步一步地运行你的Java和<strong style="color: black; background-color: #ffff66">Groovy</strong>代码，设置断点，显示变量，当前的堆栈信息等等。<br />
    <li>联合编译器：编译器<strong>将<strong style="color: black; background-color: #ffff66">Groovy</strong>和Java一起编译</strong>，可以解决语言之间的依赖问题。<br />
    <li><strong>代码补全</strong>，可以补全包，类，属性，成员变量，变量，方法，关键字，甚至对于Swing UI builder有特殊的支持。<br />
    <li>先进的类搜索和发现功能。<br />
    <li><strong>重构</strong>：大多数在Java中你所喜爱的常用重构功能都可以在Java和<strong style="color: black; background-color: #ffff66">Groovy</strong>中使用，例如&#8220;surround with&#8221;，介绍、内联或者重命名一个变量，重命名包、类、方法和成员变量。<br />
    <li><strong>导入优化和代码格式化。</strong><br />
    <li>结构视图：对你的类有一个鸟瞰视图。<br />
    </li>
</ul>
<p>最终，考虑到在IntelliJ IDEA中提供的支持和相互影响的程度，你甚至不会意识到你是在<strong style="color: black; background-color: #ffff66">Groovy</strong>中还是在Java中开发一个类。如果你正在考虑在你的Java项目中增加一些<strong style="color: black; background-color: #ffff66">Groovy</strong>或者你打算开发Grails应用，这个插件是肯定要安装的。</p>
<p>你可以在<a href="http://www.jetbrains.net/confluence/display/GRVY/Groovy+Home"><u><font color="#006600">JetBrains站点</font></u></a>得到更多信息。</p>
<p>尽管我仅仅表扬了IntelliJ IDEA的<strong style="color: black; background-color: #ffff66">Groovy</strong>插件，但是你不必因此改变你的<strong style="color: black; background-color: #ffff66">Groovy</strong>开发习惯。你可以使用由IBM的Zero项目开发者持续改进的Eclipse插件，或者Sun的NetBeans的<strong style="color: black; background-color: #ffff66">Groovy</strong>和Grails插件。</p>
<h2>性能提高<br />
</h2>
<p><strong style="color: black; background-color: #ffff66">Groovy</strong>的新版本除了增加新特性，与以前的版本相比还显著地提高了性能，并且降低了内存消耗。在我们的非正式的基准测试中，我们发现与<strong style="color: black; background-color: #ffff66">Groovy</strong> 1.5 beta版相比我们所有测试套件的运行速度有了15％到45％的提高 —— 与<strong style="color: black; background-color: #ffff66">Groovy</strong> 1.0相比肯定有更多的提高。虽然还需要开发更正式的基准测试，但是一些开发人员已经证实了这些测试数字，一家保险公司的开发人员正在使用<strong style="color: black; background-color: #ffff66">Groovy</strong>来写他们的策略风险计算引擎的商业规则，另一个公司在高并发机器上运行了多个测试。总的来说，<strong style="color: black; background-color: #ffff66">Groovy</strong>在绝大多数情况下会更快，更轻盈。不过在具体的应用中，效果还要看你如何使用<strong style="color: black; background-color: #ffff66">Groovy</strong>。</p>
<h2>增强的动态能力<br />
</h2>
<p>由于<strong style="color: black; background-color: #ffff66">Groovy</strong>和Grails项目的共生关系，Grails核心部分中成熟的动态能力已经被引入到<strong style="color: black; background-color: #ffff66">Groovy</strong>中。</p>
<p><strong style="color: black; background-color: #ffff66">Groovy</strong>是一个动态语言：简单的说，这意味着某些事情，例如方法分派发生在运行时，而不是象Java和其他语言那样发生在编译时。在<strong style="color: black; background-color: #ffff66">Groovy</strong>中有一个特殊的运行时系统，叫做MOP（元对象协议Meta-Object Protocol），负责方法分派逻辑。幸运的是，这个运行时系统非常开放，人们可以深入系统并且改变系统的通常行为。对于每一个Java类和每一个<strong style="color: black; background-color: #ffff66">Groovy</strong>实例，都有一个与之相关联的元类（meta-class）代表该对象的运行时行为。<strong style="color: black; background-color: #ffff66">Groovy</strong>为你与MOP交互提供了几种不同的方法，可以定制元类，可以继承某些基类，但是谢谢Grails项目的贡献，有一种更<strong style="color: black; background-color: #ffff66">groovy</strong>的元类：expando元类。</p>
<p>&nbsp;</p>
<p>代码例子可以帮助我们更容易地理解概念。在下面的例子中，字符串msg的实例有一个元类，我们可以通过metaClass属性访问该元类。然后我们改变<strong>String</strong>类的元类，为其增加一个新方法，为<strong>toUpperCase()</strong>方法提供一个速记记法。之后，我们为元类的up属性分配一个闭包，这个属性是在我们把闭包分配给它的时候创建的。这个闭包没有参数（因此它以一个箭头开始），我们在闭包的委托之上调用<strong>toUpperCase()</strong>方法，这个委托是一个特殊的闭包变量，代表着真实的对象（这里是String实例）。</p>
<pre><strong><strong style="color: black; background-color: #a0ffff">def</strong></strong> msg = "Hello!"
println msg.metaClass
String.metaClass.up = { -&gt; delegate.toUpperCase() }
<strong>assert</strong> "HELLO!" == msg.up()</pre>
<p>通过这个元类，你可以查询对象有哪些方法或者属性：</p>
<pre>// print all the methods
obj.metaClass.methods.each { println it.name }
// print all the properties
obj.metaClass.properties.each { println it.name }</pre>
<p>你甚至可以检查某个特定的方法或者属性是否可用，比使用instanceof来检查的粒度要小的多：</p>
<pre><strong><strong style="color: black; background-color: #a0ffff">def</strong></strong> msg = 'Hello!'
<strong>if</strong> (msg.metaClass.respondsTo(msg, 'toUpperCase')) {
println msg.toUpperCase()
}
<strong>if</strong> (msg.metaClass.hasProperty(msg, 'bytes')) {
println  foo.bytes.encodeBase64()
}</pre>
<p>这些机制在Grails web框架中得到了广泛的使用，例如创建一个动态查找器：由于你可以在一个Book领域类上调用一个<strong>findByTitle()</strong>动态方法，所以在大多数情况下不需要DAO类。通过元类，Grails自动为领域类加入了这样的方法。此外，如果被调用的方法不存在，在第一次调用的时候方法会被创建并缓存。这可以由下面解释的其他高级技巧来完成。</p>
<p>&nbsp;</p>
<p>除了我们已经看到的例子，expando元类也提供了一些补充的功能。在一个expando元类中可以加入四个其他方法：</p>
<ul>
    <li><strong>invokeMethod()</strong> 让你可以拦截所有的方法调用，<br />
    <li>而<strong>methodMissing()</strong> 仅仅在没有发现其他方法的时候被调用。<br />
    <li><strong>get/setProperty()</strong> 拦截对所有属性的访问，<br />
    <li>而<strong>propertyMissing()</strong>在没有发现属性的时候被调用。<br />
    </li>
</ul>
<p>与以前的<strong style="color: black; background-color: #ffff66">Groovy</strong>版本相比，通过expando元类可以更容易定制你的应用行为，并且节约昂贵的开发时间。很明显，不是每个人都需要使用这些技术，但是在许多场合这些技术是很方便的，例如你想应用某些AOP（面向方面的编程Aspect Oriented Techniques）来装饰你的类，或者想通过删除某些不必要的冗余代码来简化你的应用的商业逻辑代码并使其可读性更强。</p>
<h2>Steroids之上的Swing<br />
</h2>
<p><strong style="color: black; background-color: #ffff66">Groovy</strong>项目有一个天才的Swing开发者团队，他们努力工作使得在<strong style="color: black; background-color: #ffff66">Groovy</strong>中用Swing来构建用户界面的能力更强大。在<strong style="color: black; background-color: #ffff66">Groovy</strong>中构建Swing UI的基石是SwingBuilder类：在你的代码中，你可以在语法级别可视化的看到Swing组件是如何彼此嵌套的。<strong style="color: black; background-color: #ffff66">Groovy</strong> web站点的一个过分简单的例子显示了如何简单地创建一个小的GUI程序：</p>
<pre><strong>import</strong> <strong style="color: black; background-color: #ffff66">groovy</strong>.swing.SwingBuilder
<strong>import</strong> java.awt.BorderLayout
<strong>import</strong> <strong style="color: black; background-color: #ffff66">groovy</strong>.swing.SwingBuilder
<strong>import</strong> java.awt.BorderLayout <strong style="color: black; background-color: #99ff99">as</strong> BL
<strong><strong style="color: black; background-color: #a0ffff">def</strong></strong> swing = new SwingBuilder()
count = 0
<strong><strong style="color: black; background-color: #a0ffff">def</strong></strong> textlabel
<strong><strong style="color: black; background-color: #a0ffff">def</strong></strong> frame = swing.frame(title:'Frame', size:[300,300]) {
borderLayout()
textlabel = label(text:"Clicked ${count} time(s).",
constraints: BL.NORTH)
button(text:'Click Me',
actionPerformed: {count++; textlabel.text =
"Clicked ${count} time(s)."; println "clicked"},
constraints:BorderLayout.SOUTH)
}
frame.pack()
frame.show()</pre>
<p>Swing构建器的概念已经扩展到提供定制的组件工厂。有一些不是缺省包含在<strong style="color: black; background-color: #ffff66">Groovy</strong>中的附加模块，它们把JIDE或者SwingX项目中的Swing组件集成到Swing构建器代码中。</p>
<p>在这个版本中，界面部分有很多改进，值得用一整篇文章来叙述。我仅仅列出其中一部分，例如bind()方法。受到JSR (JSR-295)的bean绑定（beans binding）的启发，你可以很容易地将组件或者bean绑定到一起，使得它们在对方发生变化的时候作出反应。在下面的例子中，按钮的间隔尺寸会根据滚动条组件的值的变化而变化。</p>
<pre><strong>import</strong> <strong style="color: black; background-color: #ffff66">groovy</strong>.swing.SwingBuilder
<strong>import</strong> java.awt.Insets
swing = <strong>new</strong> SwingBuilder()
frame = swing.frame {
vbox {
slider(id: 'slider', value:5)
button('Big Button?!', margin:
<strong>bind(source: slider,
sourceProperty:'value',
converter: { [it, it, it, it] <strong style="color: black; background-color: #99ff99">as</strong> Insets }))</strong>
}
}
frame.pack()
frame.size = [frame.width + 200, frame.height + 200]
frame.show()</pre>
<p>在构建用户界面的时候将组件绑定在一起是非常常见的任务，所以这个任务通过绑定机制被简化了。还可以使用其他的自动绑定方法，但是需要一篇专门的文章来阐述。</p>
<p>在其他新的值得注意的特性中，新增了一些方便的方法，使得闭包可以调用声名狼籍的SwingUtilities类，启动新的线程：edt()将调用invokeAndWait()方法， <strong>doLater()</strong>将会调用<strong>invokeLater()</strong>方法，<strong>doOutside()</strong>方法会在一个新线程中启动一个闭包。不再有丑陋的匿名内部类：只要通过这些便捷方法使用闭包就可以！</p>
<p>最后但是也最重要的是，由于SwingBuilder的build()方法，分离视图的描述与它相关联的行为逻辑变成再简单不过的事情了。你可以创建一个仅仅包含视图的单独的脚本，而与组件的交互或者绑定都在主类中，在MVC模式中可以更清晰的分离视图与逻辑部分。</p>
<h2>总结<br />
</h2>
<p>这篇文章列出了<strong style="color: black; background-color: #ffff66">Groovy</strong> 1.5中引人注目的新特性，但是我们仅仅触及了<strong style="color: black; background-color: #ffff66">Groovy</strong>这个新版本的皮毛。重要的亮点主要围绕着Java 5的新特性，例如注解、枚举或者泛型：这使得<strong style="color: black; background-color: #ffff66">Groovy</strong>可以完美地与诸如Spring、Hibernate或者JPA这样的企业框架优美而无缝的集成。得益于改进的语法以及增强的动态能力，<strong style="color: black; background-color: #ffff66">Groovy</strong>让你能够创建内嵌的领域特定语言来定制你的商业逻辑，并在应用的扩展点将其方便地集成进来。由于工具支持的大幅改善，开发者的体验有了显著的提高，开发体验不再是采用<strong style="color: black; background-color: #ffff66">Groovy</strong>的一个障碍。总的来说，<strong style="color: black; background-color: #ffff66">Groovy</strong> 1.5前所未有的满足了简化开发者生活的目标，<strong style="color: black; background-color: #ffff66">Groovy</strong>应该成为所有Java开发者工具箱的一部分。</p>
<h2>关于作者<br />
</h2>
<p>Guillaume Laforge是<strong style="color: black; background-color: #ffff66">Groovy</strong>的项目经理和JSR-241规范的领导者，Java规范请求（Java Specification Request）在Java社区过程（Java Community Process）中标准化了<strong style="color: black; background-color: #ffff66">Groovy</strong>语言。他还是Technology的副主席以及<a href="http://www.g2one.com/"><u><font color="#006600">G2One, Inc.</font></u></a>的核心创建者，该公司资助并领导着<strong style="color: black; background-color: #ffff66">Groovy</strong>和Grails项目的发展。Guillaume经常在不同的会议谈论<strong style="color: black; background-color: #ffff66">Groovy</strong>和Grails，例如JavaOne，JavaPolis，Sun TechDays，Spring Experience，Grails eXchange。</p>
<strong>查看英文原文</strong>：<a id="wlx2" title="What's New in Groovy 1.5" href="http://www.infoq.com/articles/groovy-1.5-new"><u><font color="#006600">What's New in </font><strong style="color: black; background-color: #ffff66">Groovy</strong><font color="#006600"> 1.5</font></u></a> 
 <img src ="http://www.blogjava.net/yangvlive/aggbug/225945.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yangvlive/" target="_blank">大石头</a> 2008-08-31 21:00 <a href="http://www.blogjava.net/yangvlive/articles/225945.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>