不知道大家有没有发现在语言发展过程中,存在这么一个规律:能成为未来主流语言的,必与当前主流语言属同一‘语系’,换句话说,由王子继承王位。
在C语言之前,似乎还处于‘春秋战国’,各种编程语言混战,于 20世纪70年代,C语言成为‘秦始皇’,各种软件甚至操作系统也改用C语言编写。但可惜C语言是面向过程的,程序代码一多,逻辑流程就容易混乱,再加上全局变量和可运算指针的添乱,使程序员调试程序万般辛苦。
20世纪80年代,C++应运而生,它继承了C语言(包括C语言的语法),并添加了类等特性,使C++成为一种面向对象的语言。但C++的多继承,人工内存管理,从C语言那里继承的可运算指针等问题同样使程序员万般痛苦。
20世纪90年代,正当人们饱受煎熬的时候,Java诞生了,她去除了C++中的糟粕,保留了C++中的精华(包括语法),并添加了一些自己的特性,比如垃圾回收器,接口等。我听很多由C++转Java的朋友说过这么一句话:用Java写程序简直是一种享受。可惜Java的那优美的语法使之失去了‘轻盈’的身躯,程序员需要写相对比较多的代码来完成同样的功能。此外Java代码即使编译为class文件,也能被“高质量”反编译为Java文件获得源码。
21世纪初,Groovy( http://groovy.codehaus.org 背后有ThoughtWorks, Big Sky等公司的支持)横空出世,她几乎兼容Java的所有语法,并能无需转换直接利用Java所写的类及接口,在Spring2中可以透明地注入Groovy对象(与注入Java对象没有任何区别),且拥有自己的一些‘敏捷’特性,如动态类型,Closure,Mixins等,以及对应J2EE中如JSP, Servlet的Groovy敏捷版--GSP以及Groovlet等,不但如此她还拥有Ruby最引以为傲的Ruby on Rails的对应实现版本但非克隆--Grails( http://grails.org 背后有Oracle的支持),此外Groovy代码编译为class文件后,即使不混淆,反编译后获得的Java源代码也“极难”读懂(换句话说,如果您能读懂这些反编译得来的源码,那您早就用不着hack人家的class文件了),原因是Groovy自身就是用Java编写的,class文件烙有Groovy的印迹。 ?指代谁至今还不太明了,但Groovy至少已经具备了 继承王位的必要条件--语言本身是利用当前主流语言所编写,并与当前主流语言的语法相似,且能够结束当前主流语言的弊病。
综上所述,选择Java世界中动态语言Groovy(Groovy = Java + Python + Ruby + Smalltalk),至少是明智的,不仅因为她是JVM上JCP全票通过的官方标准语言,更因为她身上具有王储的特质。Groovy之于Java犹如Java之于C++。另外,由于Groovy本身就是用Java写的,所以对Groovy的‘投资’能够得到保值。因为Groovy的程序能运行于JDK1.4+之上,所以Groovy的新特性(比如Groovy1.1中新添加的Annotations以及static import)不会像Java中的新特性(比如Java5中的Generics以及Annotations等)那样无法在旧版JDK上使用,这就起到了保值作用。如果说Java实现了跨平台,那么Groovy不仅实现了跨平台而且实现了跨Java平台。
附关于Groovy的JCP投票结果:
再来看一个Groovy官方网站( http://groovy.codehaus.org )上的例子,在官方网站上还有许多教程和应用实例,大家不妨去看看。
利用已存在的Java类库:
import
org.apache.commons.lang.WordUtils
class Greet {
def name
Greet(who) { name = who[ 0 ].toUpperCase() + who[ 1 .. - 1 ] }
def salute() { println " Hello $name! " }
}
class Greeter extends Greet {
Greeter(who) { name = WordUtils.capitalize(who) }
}
new Greeter( ' world ' ).salute()
class Greet {
def name
Greet(who) { name = who[ 0 ].toUpperCase() + who[ 1 .. - 1 ] }
def salute() { println " Hello $name! " }
}
class Greeter extends Greet {
Greeter(who) { name = WordUtils.capitalize(who) }
}
new Greeter( ' world ' ).salute()
最后,看看Groovy与其他Java世界的动态语言的受关注程度的比较吧,从图中可以看出,Groovy有压倒性趋势:
--------------------------------------------------------------------------------------
文中提到的通过反编译获得源码:
将 HelloWorld.groovy编译为HelloWorld.class,然后将 HelloWorld.class反编译为HelloWorld.java
HelloWorld.groovy的源码:
class
HelloWorld {
static void main(String[] args) {
println " Hello, world! "
}
}
static void main(String[] args) {
println " Hello, world! "
}
}
HelloWorld.class反编译得到的Java文件HelloWorld.java:
//
Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.kpdus.com/jad.html
// Decompiler options: packimports(3)
// Source File Name: HelloWorld.groovy
import groovy.lang.GroovyObject;
import groovy.lang.MetaClass;
import org.codehaus.groovy.runtime.ScriptBytecodeAdapter;
public class HelloWorld
implements GroovyObject
{
public HelloWorld()
{
MetaClass metaclass;
Class class1 = HelloWorld. class ;
Class class2 = groovy.lang.MetaClass. class ;
metaclass = (MetaClass)ScriptBytecodeAdapter.castToType(ScriptBytecodeAdapter.invokeStaticMethodN(class1, org.codehaus.groovy.runtime.ScriptBytecodeAdapter. class , " initMetaClass " , new Object[] {
this
}), class2);
metaclass;
(MetaClass)ScriptBytecodeAdapter.castToType(metaclass, class2);
this ;
JVM INSTR swap ;
metaClass;
JVM INSTR pop ;
}
public static void main(String args[])
{
Class class1 = HelloWorld. class ;
Class class2 = groovy.lang.MetaClass. class ;
ScriptBytecodeAdapter.invokeStaticMethodN(class1, class1, " println " , new Object[] {
" Hello, world! "
});
}
public MetaClass getMetaClass()
{
Class class2;
MetaClass metaclass;
Class class1 = HelloWorld. class ;
class2 = groovy.lang.MetaClass. class ;
if ( ! ScriptBytecodeAdapter.compareEqual(metaClass, null ))
break MISSING_BLOCK_LABEL_118;
metaclass = (MetaClass)ScriptBytecodeAdapter.castToType(ScriptBytecodeAdapter.invokeStaticMethodN(class1, org.codehaus.groovy.runtime.ScriptBytecodeAdapter. class , " initMetaClass " , new Object[] {
this
}), class2);
metaclass;
(MetaClass)ScriptBytecodeAdapter.castToType(metaclass, class2);
this ;
JVM INSTR swap ;
metaClass;
JVM INSTR pop ;
return (MetaClass)ScriptBytecodeAdapter.castToType(metaClass, class2);
}
public Object invokeMethod(String method, Object arguments)
{
Class class1;
MetaClass metaclass;
class1 = HelloWorld. class ;
Class class2 = groovy.lang.MetaClass. class ;
if ( ! ScriptBytecodeAdapter.compareEqual(metaClass, null ))
break MISSING_BLOCK_LABEL_121;
metaclass = (MetaClass)ScriptBytecodeAdapter.castToType(ScriptBytecodeAdapter.invokeStaticMethodN(class1, org.codehaus.groovy.runtime.ScriptBytecodeAdapter. class , " initMetaClass " , new Object[] {
this
}), class2);
metaclass;
(MetaClass)ScriptBytecodeAdapter.castToType(metaclass, class2);
this ;
JVM INSTR swap ;
metaClass;
JVM INSTR pop ;
return ScriptBytecodeAdapter.invokeMethodN(class1, metaClass, " invokeMethod " , new Object[] {
this , method, arguments
});
}
public Object getProperty(String property)
{
Class class1;
MetaClass metaclass;
class1 = HelloWorld. class ;
Class class2 = groovy.lang.MetaClass. class ;
if ( ! ScriptBytecodeAdapter.compareEqual(metaClass, null ))
break MISSING_BLOCK_LABEL_118;
metaclass = (MetaClass)ScriptBytecodeAdapter.castToType(ScriptBytecodeAdapter.invokeStaticMethodN(class1, org.codehaus.groovy.runtime.ScriptBytecodeAdapter. class , " initMetaClass " , new Object[] {
this
}), class2);
metaclass;
(MetaClass)ScriptBytecodeAdapter.castToType(metaclass, class2);
this ;
JVM INSTR swap ;
metaClass;
JVM INSTR pop ;
return ScriptBytecodeAdapter.invokeMethodN(class1, metaClass, " getProperty " , new Object[] {
this , property
});
}
public void setProperty(String property, Object value)
{
Class class1;
MetaClass metaclass;
class1 = HelloWorld. class ;
Class class2 = groovy.lang.MetaClass. class ;
if ( ! ScriptBytecodeAdapter.compareEqual(metaClass, null ))
break MISSING_BLOCK_LABEL_121;
metaclass = (MetaClass)ScriptBytecodeAdapter.castToType(ScriptBytecodeAdapter.invokeStaticMethodN(class1, org.codehaus.groovy.runtime.ScriptBytecodeAdapter. class , " initMetaClass " , new Object[] {
this
}), class2);
metaclass;
(MetaClass)ScriptBytecodeAdapter.castToType(metaclass, class2);
this ;
JVM INSTR swap ;
metaClass;
JVM INSTR pop ;
ScriptBytecodeAdapter.invokeMethodN(class1, metaClass, " setProperty " , new Object[] {
this , property, value
});
return ;
}
public void setMetaClass(MetaClass value)
{
Class class2;
Class class1 = HelloWorld. class ;
class2 = groovy.lang.MetaClass. class ;
value;
(MetaClass)ScriptBytecodeAdapter.castToType(value, class2);
this ;
JVM INSTR swap ;
metaClass;
JVM INSTR pop ;
}
void super $ 1 $wait()
{
super .wait();
}
String super $ 1 $toString()
{
return super .toString();
}
void super $ 1 $wait( long l)
{
super .wait(l);
}
void super $ 1 $notify()
{
super .notify();
}
void super $ 1 $notifyAll()
{
super .notifyAll();
}
Class super $ 1 $getClass()
{
return super .getClass();
}
boolean super $ 1 $equals(Object obj)
{
return super .equals(obj);
}
Object super $ 1 $clone()
{
return super .clone();
}
int super $ 1 $hashCode()
{
return super .hashCode();
}
void super $ 1 $wait( long l, int i)
{
super .wait(l, i);
}
void super $ 1 $finalize()
{
super .finalize();
}
transient MetaClass metaClass;
public static Long __timeStamp;
static
{
Long long1;
Class class1 = HelloWorld. class ;
Class class2 = groovy.lang.MetaClass. class ;
long1 = new Long( 0x1121e0ead4dL );
Long _tmp = long1;
__timeStamp = (Long)long1;
}
}
// Jad home page: http://www.kpdus.com/jad.html
// Decompiler options: packimports(3)
// Source File Name: HelloWorld.groovy
import groovy.lang.GroovyObject;
import groovy.lang.MetaClass;
import org.codehaus.groovy.runtime.ScriptBytecodeAdapter;
public class HelloWorld
implements GroovyObject
{
public HelloWorld()
{
MetaClass metaclass;
Class class1 = HelloWorld. class ;
Class class2 = groovy.lang.MetaClass. class ;
metaclass = (MetaClass)ScriptBytecodeAdapter.castToType(ScriptBytecodeAdapter.invokeStaticMethodN(class1, org.codehaus.groovy.runtime.ScriptBytecodeAdapter. class , " initMetaClass " , new Object[] {
this
}), class2);
metaclass;
(MetaClass)ScriptBytecodeAdapter.castToType(metaclass, class2);
this ;
JVM INSTR swap ;
metaClass;
JVM INSTR pop ;
}
public static void main(String args[])
{
Class class1 = HelloWorld. class ;
Class class2 = groovy.lang.MetaClass. class ;
ScriptBytecodeAdapter.invokeStaticMethodN(class1, class1, " println " , new Object[] {
" Hello, world! "
});
}
public MetaClass getMetaClass()
{
Class class2;
MetaClass metaclass;
Class class1 = HelloWorld. class ;
class2 = groovy.lang.MetaClass. class ;
if ( ! ScriptBytecodeAdapter.compareEqual(metaClass, null ))
break MISSING_BLOCK_LABEL_118;
metaclass = (MetaClass)ScriptBytecodeAdapter.castToType(ScriptBytecodeAdapter.invokeStaticMethodN(class1, org.codehaus.groovy.runtime.ScriptBytecodeAdapter. class , " initMetaClass " , new Object[] {
this
}), class2);
metaclass;
(MetaClass)ScriptBytecodeAdapter.castToType(metaclass, class2);
this ;
JVM INSTR swap ;
metaClass;
JVM INSTR pop ;
return (MetaClass)ScriptBytecodeAdapter.castToType(metaClass, class2);
}
public Object invokeMethod(String method, Object arguments)
{
Class class1;
MetaClass metaclass;
class1 = HelloWorld. class ;
Class class2 = groovy.lang.MetaClass. class ;
if ( ! ScriptBytecodeAdapter.compareEqual(metaClass, null ))
break MISSING_BLOCK_LABEL_121;
metaclass = (MetaClass)ScriptBytecodeAdapter.castToType(ScriptBytecodeAdapter.invokeStaticMethodN(class1, org.codehaus.groovy.runtime.ScriptBytecodeAdapter. class , " initMetaClass " , new Object[] {
this
}), class2);
metaclass;
(MetaClass)ScriptBytecodeAdapter.castToType(metaclass, class2);
this ;
JVM INSTR swap ;
metaClass;
JVM INSTR pop ;
return ScriptBytecodeAdapter.invokeMethodN(class1, metaClass, " invokeMethod " , new Object[] {
this , method, arguments
});
}
public Object getProperty(String property)
{
Class class1;
MetaClass metaclass;
class1 = HelloWorld. class ;
Class class2 = groovy.lang.MetaClass. class ;
if ( ! ScriptBytecodeAdapter.compareEqual(metaClass, null ))
break MISSING_BLOCK_LABEL_118;
metaclass = (MetaClass)ScriptBytecodeAdapter.castToType(ScriptBytecodeAdapter.invokeStaticMethodN(class1, org.codehaus.groovy.runtime.ScriptBytecodeAdapter. class , " initMetaClass " , new Object[] {
this
}), class2);
metaclass;
(MetaClass)ScriptBytecodeAdapter.castToType(metaclass, class2);
this ;
JVM INSTR swap ;
metaClass;
JVM INSTR pop ;
return ScriptBytecodeAdapter.invokeMethodN(class1, metaClass, " getProperty " , new Object[] {
this , property
});
}
public void setProperty(String property, Object value)
{
Class class1;
MetaClass metaclass;
class1 = HelloWorld. class ;
Class class2 = groovy.lang.MetaClass. class ;
if ( ! ScriptBytecodeAdapter.compareEqual(metaClass, null ))
break MISSING_BLOCK_LABEL_121;
metaclass = (MetaClass)ScriptBytecodeAdapter.castToType(ScriptBytecodeAdapter.invokeStaticMethodN(class1, org.codehaus.groovy.runtime.ScriptBytecodeAdapter. class , " initMetaClass " , new Object[] {
this
}), class2);
metaclass;
(MetaClass)ScriptBytecodeAdapter.castToType(metaclass, class2);
this ;
JVM INSTR swap ;
metaClass;
JVM INSTR pop ;
ScriptBytecodeAdapter.invokeMethodN(class1, metaClass, " setProperty " , new Object[] {
this , property, value
});
return ;
}
public void setMetaClass(MetaClass value)
{
Class class2;
Class class1 = HelloWorld. class ;
class2 = groovy.lang.MetaClass. class ;
value;
(MetaClass)ScriptBytecodeAdapter.castToType(value, class2);
this ;
JVM INSTR swap ;
metaClass;
JVM INSTR pop ;
}
void super $ 1 $wait()
{
super .wait();
}
String super $ 1 $toString()
{
return super .toString();
}
void super $ 1 $wait( long l)
{
super .wait(l);
}
void super $ 1 $notify()
{
super .notify();
}
void super $ 1 $notifyAll()
{
super .notifyAll();
}
Class super $ 1 $getClass()
{
return super .getClass();
}
boolean super $ 1 $equals(Object obj)
{
return super .equals(obj);
}
Object super $ 1 $clone()
{
return super .clone();
}
int super $ 1 $hashCode()
{
return super .hashCode();
}
void super $ 1 $wait( long l, int i)
{
super .wait(l, i);
}
void super $ 1 $finalize()
{
super .finalize();
}
transient MetaClass metaClass;
public static Long __timeStamp;
static
{
Long long1;
Class class1 = HelloWorld. class ;
Class class2 = groovy.lang.MetaClass. class ;
long1 = new Long( 0x1121e0ead4dL );
Long _tmp = long1;
__timeStamp = (Long)long1;
}
}
附: 通过与Java的比较,迅速掌握Groovy