疯狂java


您现在的位置: 疯狂软件 >> 新闻资讯 >> 正文

用 Java 生成 Java - CodeModel 介绍


 

         在我们编写代码的时候,常常会有这样的情形:一部分代码是可以根据另一部分代码按照某种特定的模式变化而来的;有时,随着那一部分被依赖的代码发生变化,依赖的代码不得不跟着修改;有时,这样的代码会随着项目的推进,不止一次的出现。很典型的一个例子就是,当需要自己实现数据访问层时,通常每个实体类会对应一个 DAO(数据访问对象)类,并且一般来讲 DAO 类的代码编写是很机械的。这时,我们就需要使用“代码生成”来提高我们的开发效率以及提高代码的可维护性。

  Java 有很多种方法可以实现“代码生成”,比如,直接使用打印语句或者使用模板引擎。但相比较而言,使用 CodeModel 会使代码更灵活也更容易维护。CodeModel 的官网除了 Javadoc 没有提供很好的学习文档,所以我们在项目中使用时也是不断地摸索。因此,本文既是一篇 CodeModel 的介绍文章,也是我们对 CodeModel 使用的经验总结。本文将按照一般的学习编程语言的思路并结合示例代码向读者朋友们介绍 CodelModel 的使用方法。希望能对读者朋友们有所帮助。

  CodeModel 简介

  CodeModel 是用于生成 Java 代码的 Java 库,它提供了一种通过 Java 程序来生成 Java 程序的方法。

  CodeModel 项目是 JAXB 的子项目。JAXB(Java Architecture for XML Binding)是一项可以根据 XML Schema 产生 Java 类的技术,它提供了将 XML 实例文档反向生成 Java 对象树的方法,并能将 Java 对象树的内容重新写到 XML 实例文档。JAXB 是 JDK 的组成部分。JAXB RI(Reference Implementation)即 schema compiler 能够将 XML 的 schema 文件映射为相应的 Java 元素。

  回页首

  CodeModel 的使用方法

  如果去阅读 JCodeModel 的 API 文档,JCodeModel 类是我们第一个要去接触的。JCodeModel 类是生成 Java 代码的根。通常我们按照自上而下的顺序生成所需要的 Java 代码。比如首先创建一个类 JDefinedClass,然后再通过类生成方法、方法体以及方法体内的代码……依次而下。

  一个 CodeModel 的典型应用如下:

  清单 1. CodeModel 的典型应用

  JCodeModel cm = new JCodeModel();

  // 通过构建 cm 树来生成 Java 代码

  cm._class(...);

  ...

  // 自上而下地生成类、方法等

  cm.build(new File("."));

  在 CodeModel 中除了 JCodeModel 类,几个常用的类有 JDefinedClass、JMethod、JBlock、JFieldVar、JVar、JType、JExpr 等。

  JDefinedClass 类是 CodeModel 来定义类的,它提供了类自身的创建、继承、实现,以及类成员变量、成员方法的创建方法等

  JMethod 类是 Java 的方法类,它可以创建方法体,那么就有了 JBlock 类

  JBlock 类是我们经常要用到的类,它提供了非常多的方法:局部变量的声明、变量赋值、生成各种控制语句、调用其他方法、设置方法的返回值等

  JFieldVar 类用来定义类的成员变量,它可以对成员变量进行声明、赋值等

  JVar 类用来定义变量,提供了变量的基本操作如声明、赋值、初始化等

  JType 类用来定义 Java 中的各种数据类型

  JExpr 类表达式的工厂类,它提供了 TRUE 和 FALSE 两个常量值,以及生成表达式的各种方法以及表达式的赋值等

  为了方便后面的代码演示,现在这里构建好 cm 树和 dc 类,CodeModel 会在当前项目的 src 文件夹 -> dw 包下生成名为 example 的 Java 类。

  清单 2. 构建 cm 树和 dc 类

  File destDir = new File ((new File("src"));

  JCodeModel cm = new JCodeModel();// 实例化 CodeModel

  JDefinedClass dc = cm._class("dw.example"); // 创建 example 类

  变量声明与赋值

  变量类型

  Java 的变量类型包括基本数据类型和引用数据类型。

  JCodeModel 类中定义了几个常量来映射 Java 的基本数据类型。

  JCodeModel 的成员常量 BOOLEAN、BYTE、CHAR、SHORT、INT、LONG、FLOAT 和 DOUBLE 涵盖了 Java 所有的基本数据类型(boolean、byte、char、short、int、long、float、double),以及 NULL、VOID 等。可以通过 cm 直接得到。

  关于引用类型,可以通过 JCodeModel 类的 parseType 方法来得到。在 parseType 方法的参数中指定要引用的类型,通过类型名来获取对象。

  清单 3. 获取引用变量类型

  JType type = cm.parseType("String");

  JType type1 = cm.parseType("myType");

  之后便可以使用 type、type1 来定义变量的类型。

  本地变量和成员变量

  Java 的变量可以分为本地变量(也成为局部变量)和成员变量(也成为实例变量)。

  对于本地变量,可以使用 JBlock 类中的 decl 方法对本地变量进行定义和初始化。本地变量是 JVar 类型。JBlock 类提供了三个重载的 decl 方法,分别是:

  decl(int mods, JType type, String name, JExpression init)

  decl(JType type, String name)

  decl(JType type, String name, JExpression init)

  上面的方法通过 int mods 来定义变量的修饰符,mods 来自 CodeModel 的 JMod 类。JMod 类定义了一些 Java 的修饰符常量,包括 ABSTRACT、FINAL、PRIVATE、PROTECTED、PUBLIC、STATIC、SYNCHRONIZED 等。如果要使用多个修饰符,可以通过“+”来实现;

  通过 type 来定义变量的类型;通过 name 来定义变量的名字;通过 init 来定义变量的初始值。

  清单 4. 生成 Java 本地变量

  JMethod exampleMethod = dc.method(JMod.PUBLIC, cm.VOID, "exampleMethod");

  JBlock exampleMethodBlk = exampleMethod.body();

  JVar var = exampleMethodBlk.decl(type, "fieldVar");

  JVar var1 = exampleMethodBlk.decl(type, "fieldVar1",JExpr.lit(5));

  以上代码创建了名为 exampleMethod 的方法,并创建了该方法的方法体 exampleMethodBlk,通过方法体的 decl 方法创建了这个方法的变量 var 和 var1,并给变量 var1 赋了初始值。

  代码的运行结果为:

  public void exampleMethod() {

  int fieldVar;

  int fieldVar1 = 5;

  }

  对于 Java 的成员变量,可以通过 JDefinedClass 类的 field 方法来生成。成员变量是 JFieldVar 类型的。JDefinedClass 类提供了四个重载的 field 方法来生成成员变量如下,通过 mods 来定义成员变量的修饰符;通过 type 来定义变量的类型;通过 name 来定义变量的名字;通过 init 来定义变量的初始值。

  field(int mods, Class type, String name)

  field(int mods, Class type, String name, JExpression init)

  field(int mods, JType type, String name)

  field(int mods, JType type, String name, JExpression init)

  清单 5. 生成 Java 成员变量

  JFieldVar fVar = dc.field(JMod.PUBLIC, cm.INT, "a");

  JFieldVar fVar1 = dc.field(JMod.PRIVATE, cm.parseType("String"), "b", JExpr.lit(“abc”));

  代码的运行结果为:

  public class example {

  public static a;

  private String b = “abc”;

  }

  静态变量和常量

  要定义静态变量,只需要在生成变量方法的修饰符处定义 static 即可。和静态变量类似的,常量则需要在修饰符处定义 final。

  清单 6. 生成静态变量和常量

  dc.field(JMod.PRIVATE + JMod.STATIC, cm.parseType("String"),

  "staticVar", JExpr.lit("abc"));

  dc.field(JMod.PUBLIC + JMod.FINAL, cm.INT, "MAX_ARRAY_SIZE",JExpr.lit(25));

  以上代码的运行结果为:

  private static String staticVar= "abc";

  public final int MAX_ARRAY_SIZE = 25;

  变量赋值

  CodeModel 库中的 JExpr 类提供了生成表达式(JExpression 类型)的各种方法。JExpr 类的 lit 方法可以生成 Java 基本数据类型的表达式,作为变量初始化的值。

  lit(boolean b) // 布尔类型

  lit(char c) // 字符型

  lit(int n) // 整型

  lit(long n) // 长整型

  lit(double d) // 双精度浮点型

  lit(float f) // 单精度浮点型

  lit(String s) // 字符串类型

  在本文前面的示例代码中,都有对变量的定义和赋值,但基本上是针对 Java 的基本数据类型,那么对于引用数据类型,CodeModel 是如何使用的呢?

  对于数组类型,只需要将要定义的数组类型通过 parseType 获取到,通过 JExpr 的 newArray 方法生成数组类型变量,使用 CodeModel 的数组类 JArray 的 add 方法来进行数组变量的初始化。JExpr 类提供了三个重载的 newArray 方法如下,分别可以定义数组的类型 type、数组的长度 size。

  newArray(JType type)

  newArray(JType type, int size)

  newArray(JType type, JExpression size)

  清单 7. 数组变量的生成与赋值

  JType arrType = cm.parseType("int []"); // 定义数组类型

  JArray initArray = JExpr.newArray(cm.INT); // 创建类型为整型的数组

  dc.field(JMod.PUBLIC, arrType, "arr", initArray);

  initArray.add(JExpr.lit(0));

  initArray.add(JExpr.lit(1));

  运行结果为:

  public class example {

  public int[] arr = new int[ ] { 0, 1 };

  }

  关于 Java 其他引用类型 - 类和接口的定义和使用,后面会详细介绍。

  变量的强制类型转换

  CodeModel JVar 类的 cast 方法可以实现变量间的强制类型转换。在 cast 的参数中执行要转换的类型(JType type)和需要转换的变量表达式(JExpression expr)即可。

  清单 8. 变量的强制类型转换

  JVar longValue = exampleMethodBlk.decl(cm.LONG, "longValue",JExpr.lit(99L));

  JVar intValue = exampleMethodBlk.decl(cm.INT, "intValue",

  JExpr.cast(cm.INT, JExpr.ref("longValue")));

  运行结果如下:

  long longValue = 99L;

  int intValue = ((int) longValue)

  类和接口

  实体类和抽象类

  在 CodeModel 的 JCodeModel 类和 JDefinedClass 类中都提供了生成类的方法 _class。

  可以使用 JCodeModel 类中的 _class 方法来生成 Java 实体类或抽象类。JCodeModel 类提供了三个重载的 _class 方法来生成类。通过 mods 来指定类的修饰符,通过 fullyqualifiedName 来指定类的完全限定名,通过 t 来指定类的类型。如果要生成抽象类,则可以指定类的修饰符为 ABSTRACT。

  _class(int mods, String fullyqualifiedName, ClassType t)

  _class(String fullyqualifiedName)

  _class(String fullyqualifiedName, ClassType t)

  在 JDefinedClass 类中有四个生成类的方法 _class 如下,用来在一个类中生成嵌套的类。对于方法中的参数,可以通过 mods 来指定类的修饰符,name 来指定类的名字,classTypeVal 来指定类的类型,isInterface 来指定是否为接口。

  _class(int mods, String name)

  _class(int mods, String name, boolean isInterface)

  _class(int mods, String name, ClassType classTypeVal)

  _class(String name)

  清单 9. 生成类

  JDefinedClass exampleClass = cm._class("dw.examples.exampleClass");

  exampleClass.method(JMod.PUBLIC, cm.VOID, "methodA").body().invoke("dosomething");

  代码运行结果如下,生成了实体类 exampleClass:

  public class exampleClass {

  public void methodA() {

  dosomething();

  }

  }

  Java 的抽象类不能直接使用,必须用子类去实现抽象类,然后使用其子类的实例。下面的代码演示如果通过子类实现抽象类。

  清单 10. 通过子类实现抽象类

  // 生成抽象类

  JDefinedClass abstractClass = cm._class(JMod.PUBLIC + JMod.ABSTRACT,

  "dw.examples.abstractClass", ClassType.CLASS);

  abstractClass.method(JMod.PUBLIC + JMod.ABSTRACT, cm.VOID, "methodB");

  代码运行结果如下,生成了抽象类 abstractClass:

  public abstract class abstractClass {

  public abstract void methodB();

  }

  // 子类实现抽象类

  JDefinedClass sonClass = cm._class(JMod.PUBLIC,"dw.examples.sonClass",ClassType.CLASS);

  sonClass._extends(abstractClass);

  sonClass.method(JMod.PUBLIC, cm.VOID, "methodB").body().invoke("dosomething");

  代码运行结果为:

  public class generatedSonClass extends generatedAbstractClass

  {

  public void methodB() {

  dosomething();

  }

  }

  接口

  接口的生成和类相似,可以通过 JCodeModel 的 _class 方法来生成。需要在 _class 方法的参数中指定类型为接口。在 ClassType 类中定义了几个常量类型,包括 CLASS、INTERFACE、ENUM 等。因此设定 _class 方法的参数 t 为 ClassType.INTERFACE 就可以了。

  也可以使用 JDefinedClass 类中的 _class 方法,通过指定 isInterface 为 true 来在类中生成嵌套的接口。

  清单 11. 生成接口

  JDefinedClass exampleInterface = cm._class(JMod.PUBLIC,

  "dw.examples.Runner", ClassType.INTERFACE);

  exampleInterface.field(0, cm.INT, "ID", JExpr.lit(1));

  exampleInterface.method(JMod.PUBLIC, cm.VOID, "start");

  exampleInterface.method(JMod.PUBLIC, cm.VOID, "run");

  exampleInterface.method(JMod.PUBLIC, cm.VOID, "stop");

  代码运行结果为:

  public interface Runner {

  int ID = 1;

  public void start();

  public void run();

  public void stop();

  }

  接口需要通过类来实现,以下代码演示如何通过类来实现接口。

  清单 12. 通过类实现接口

  JDefinedClass impClass = cm._class(JMod.PUBLIC,"dw.examples.Person",ClassType.CLASS);

  impClass._implements(exampleInterface);

  impClass.method(JMod.PUBLIC, cm.VOID, "start").body().invoke("actions");

  impClass.method(JMod.PUBLIC, cm.VOID, "run").body().invoke("actions");

  impClass.method(JMod.PUBLIC, cm.VOID, "stop").body().invoke("actions");

  生成的代码如下:

  public class Person

  implements Runner

  {

  public void start() {

  actions();

  }

  public void run() {

  actions();

  }

  public void stop() {

  actions();

  }

  }

  类的调用

  对于 Java 的基本类,可以通过 JCodeModel 类的 ref 方法来实现。JCodeModel 类提供了两个重载的 ref 方法,可以通过类对象和类的完全限定名来调用。

  ref(Class clazz)

  ref(String fullyQualifiedClassName)

  清单 13. 基本类的调用

  JBlock body = exampleMethod.body();

  JClass sys = cm.ref("java.lang.System");

  body.invoke(sys.staticRef(“out”),”println”).arg(“HelloWorld!”);

  而对于自定义类的引用,则可以通过 JExpr 类的 _new 方法来实例化,通过 JBlock 类的 assign 方法可以实现赋值。JExpr 类提供了两个 _new 方法来实现类的使用。通过方法 _new(JClass c) 和 _new(JType t) 的参数可以指定生成对象的类型。

  清单 14. 自定义类的调用

  // 生成 myDate 类,它有 day、month、year 三个变量

  dc.field(0, cm.INT, "day");

  dc.field(0, cm.INT, "month");

  dc.field(0, cm.INT, "year");

  JType classType = cm.parseType("myDate"); // 定义类的类型

  JMethod newMyDate = dc.method(JMod.PUBLIC, cm.VOID, "newMyDate"); // 创建公共方法 newMyDate

  JBlock blk = newMyDate.body();

  JVar today = blk.decl(classType, "today"); // 定义变量

  blk.assign(today, JExpr._new(classType)); // 创建新的类对象并将它赋给 today

  生成的代码如下:

  public class myDate {

  int day;

  int month;

  int year;

  public void newMyDate() {

  myDate today;

  today = new myDate();

  }

  }

  方法

  方法的定义

  对于 Java 类的构造方法,需要使用 JDefinedClass 类的 constructor 方法来生成,而对于类的成员方法,则可以通过 JDefinedClass 类的 method 方法来定义和生成。JDefinedClass 有两个重载的 method 方法。可以定义方法的修饰符 mods、返回值类型 type 以及方法名 name。如果方法是抽象的,则需设定 mods 为 ABSTRACT。

  method(int mods, Class type, String name)

  method(int mods, JType type, String name)

  清单 15. 构造方法和成员方法的生成

  dc.constructor(JMod.PUBLIC);

  dc.method(JMod.PUBLIC, methodType, "exampleMethod");

  第一行代码就生成了类的公共的构造方法。第二行代码则通过 method 方法生成了类的一个公共的成员方法 exampleMethod。

  方法的调用

  方法的调用是通过 JBlock 类的 invoke 方法来实现的。JBlock 类提供了四个 invoke 方法,可以设定方法的调用者 expr,也可以不指定调用者直接通过方法名 method 使用。

  invoke(JExpression expr, JMethod method)

  invoke(JExpression expr, String method)

  invoke(JMethod method)

  invoke(String method)

  清单 16. 方法的调用

  exampleBlk.invoke(JExpr.ref("expA"), "methodB").arg("argA");

  运行结果如下:

  expA.methodB(“argA”);

  控制语句

  条件语句(if,switch)

  Java 支持双路 if 和多路 switch 分支语句。

  在 CodeModel 中,使用 JBlock 类中的 _if 方法来生成 if 控制语句,方法 _if(JExpression expr) 的参数中可以指定 if() 的布尔表达式。而 else 块是通过 if 块(JConditional 类)的方法 _else 来生成的,else 部分是选择性的。JConditional 类还提供了 _elseif 方法来创建 else if ( … ) 语句。

  清单 17. if 语句代码演示

  JConditional outerIf = exampleBlk._if(JExpr.ref("a1").gt(JExpr.ref("a2")));

  JBlock outerThen = outerIf._then();

  JBlock outerElse = outerIf._else();

  JConditional innerIf = outerThen._if(JExpr.ref("a1").gt(JExpr.ref("a3")));

  JBlock innerThen = innerIf._then();

  JBlock innerElse = innerIf._else();

  生成的代码如下:

  if (a1 >a2) {

  if (a1 >a3) {

  } else {

  }

  } else {

  }

  Java 中的 switch 语句,是通过 JBlock 类的 _switch 方法来生成的。而 switch 中的 case 语句,则是通过 JSwitch 类的 _case 方法生成的。要生成某个 case 代码段,就需要使用 JCase 类的 body 方法来生成方法体,然后在该方法体内增加其他代码。

  清单 18. switch 语句代码演示

  exampleBlk.decl(cm.INT, "colorNum", JExpr.lit(0));

  JSwitch exampleSwitch = exampleBlk._switch(JExpr.ref("colorNum"));

  JCase caseA = exampleSwitch._case(JExpr.lit(0));

  caseA.body().invoke("caseA");

  JCase caseB = exampleSwitch._case(JExpr.lit(1));

  JBlock caseBBody = caseB.body();

  caseBBody.invoke("caseB");

  caseBBody._break();

  JCase caseC = exampleSwitch._case(JExpr.lit(2));

  caseC.body()._break();

  生成的代码如下:

  int colorNum = 0;

  switch (colorNum) {

  case 0 :

  caseA();

  case 1 :

  caseB();

  break;

  case 2 :

  break;

  }

  循环语句(for,while,do … while)

  Java 支持三种循环构造类型:for、while 和 do。

  对于 for 循环,使用 CodeModel JBlock 类的 _for 方法来生成一个 for 语句。

  for 语句的初始表达式则需要 JForLoop 类的 init 方法来生成,JForLoop 类提供了三个重载的 init 方法,可以指定变量的修饰符(int mods)、类型(JType type)、名字(String var)以及初始值(JExpression e)。

  init(int mods, JType type, String var, JExpression e)

  init(JType type, String var, JExpression e)

  init(JVar v, JExpression e)

  for 语句的测试表达式是由 JForLoop 类的 test 方法生成的,test 方法通过 JExpression e 指定测试表达式。

  test(JExpression e)

  for 语句的改变量表达式是由 JForLoop 类的 update 方法生成的,update 方法通过 JExpression e 指定改变变量表达式。

  update(JExpression e)

  清单 19. for 语句代码演示

  JForLoop exampleFor = exampleBlk._for();

  exampleFor.init(cm.INT,"i", JExpr.lit(0));

  exampleFor.test(JExpr.ref("i").lt(JExpr.lit(10)));

  exampleFor.update(JExpr.ref("i").incr());

  JBlock forBody = exampleFor.body();

  forBody.invoke("dosomething");

  运行结果如下:

  for (int i = 0; (i< 10); i ++) {

  dosomething();

  }

  Java 的 while 循环是通过 CodeModel JBlock 类的 _while 方法生成的,通过 _while 方法的参数 JExpression test 来定义 while 循环的表达式。

  _while(JExpression test)

  清单 20. while 语句代码演示

  JVar i = exampleBlk.decl(cm.INT, "i", JExpr.lit(0));

  JWhileLoop exampleWhile = exampleBlk._while(JExpr.ref("i").lt(

  JExpr.lit(10)));

  JBlock whileBody = exampleWhile.body();

  whileBody.invoke("dosomething");

  whileBody.assignPlus(i, JExpr.lit(1));

  运行结果为:

  int i = 0;

  while (i< 10) {

  dosomething();

  i += 1;

  }

  Java 的 do 循环是通过 CodeModel JBlock 类的 _do 方法生成的,通过 _do 方法的 JExpression test 来定义 do while 循环的表达式。

  _do(JExpression test)

  清单 21. do … while 语句代码演示

  JVar i = exampleBlk.decl(cm.INT, "i", JExpr.lit(0));

  JDoLoop exampleDo = exampleBlk._do(JExpr.ref("i").lt(JExpr.lit(10)));

  JBlock doBody = exampleDo.body();

  doBody.invoke("dosomething");

  doBody.assignPlus(i, JExpr.lit(1));

  运行结果为:

  int i = 0;

  do {

  dosomething();

  i += 1;

  } while (i< 10);

  转移语句(break,continue)

  Java 中的 break 和 continue 用于特殊循环流程控制,可以通过 CodeModel JBlock 类中的 _break 和 _continue 来生成。此处不再详述。

  注释与 Javadoc

  注释与 Javadoc 也是 Java 程序中不可或缺的部分。使用 CodeModel JDefinedClass 类中的 javadoc 方法或 Jmethod 类中的 javadoc 方法可以用来生成类级或方法级的 Javadoc。

  方法 javadoc 的返回类型为 JDocComment 类型。该 JDocComment 类的方法 addParam 可以生成 @param 标签,addReturn 生成 @return 标签,addThrows 生成 @throws 标签,addXdoclet 生成特殊的注释信息等。JDocComment 类的 add 方法可以生成 Javadoc 的内容。后面的实例分析会有关于生成注释和 Javadoc 的代码,在此不再做代码演示。

  回页首

  实例分析:使用 CodeModel 实现一个单例生成器

  如何实现单例类生成器

  我们来分析一下:要实现一个单例生成器,需要首先创建一个 Singleton 类,在该类中定义一个静态成员变量 instance。我们可以用代码生成该类的构造函数 Singleton()。Singleton 类还必须有一个静态的公共的方法来获取到实例,我们将其命名为 getInstance(),此外,我们给 Singleton 类创建一个名为 sayHello() 的成员方法,让其打印出传入的参数。

  为了测试我们的 Singleton 类,我们再让程序生成另外一个类 singletonTest,这个类将通过 Singleton 类的 getInstance() 方法得到一个单例实例,再调用 sayHello() 方法打印出“Hello CodeModel!”。

  有了以上的分析,结合之前介绍的 CodeModel 生成类、变量、方法以及控制语句的方法,代码就很容易写出来的。

  代码详解

  清单 22. 代码 SingletonGen 来实现单例生成器

  package dw;

  import java.io.File;

  import com.sun.codemodel.JBlock;

  import com.sun.codemodel.JClass;

  import com.sun.codemodel.JCodeModel;

  import com.sun.codemodel.JDefinedClass;

  import com.sun.codemodel.JConditional;

  import com.sun.codemodel.JDocComment;

  import com.sun.codemodel.JExpr;

  import com.sun.codemodel.JExpression;

  import com.sun.codemodel.JFieldRef;

  import com.sun.codemodel.JInvocation;

  import com.sun.codemodel.JMethod;

  import com.sun.codemodel.JMod;

  import com.sun.codemodel.JType;

  /**

  * This class will generate a singleton class "Singleton.java" and a test class

  * "SingletonTest.java" under the specified package.

  *

  * @author Sonia (sxyu@cn.ibm.com)

  *

  */

  public class SingletonGen {

  public void genSingleton() throws Exception {

  JCodeModel cm = new JCodeModel();

  JType type = cm.parseType("Singleton");

  File destDir = new File("src");

  JDefinedClass dc = cm._class("dw.sample.Singleton");

  // 定义静态成员变量

  dc.field(JMod.PRIVATE+ JMod.STATIC, type, "instance");

  // 定义单例类 Singleton 的构造函数

  dc.constructor(JMod.PRIVATE);

  // 生成 Singleton 类的成员方法 getInstanceMethod

  JMethod getInstanceMethod = dc.method(JMod.PUBLIC+ JMod.STATIC, type,

  "getInstance");

  JBlock getInstanceBody = getInstanceMethod.body();

  JFieldRef fieldRef = JExpr.ref("instance");

  JConditional conditionIf = getInstanceBody._if(fieldRef.eq(JExpr

  ._null()));

  JBlock thenPart = conditionIf._then();

  thenPart.assign(fieldRef, JExpr._new(type));

  getInstanceBody._return(fieldRef);

  // 生成 Singleton 类的成员方法 sayHelloMethod

  JMethod sayHelloMethod = dc.method(JMod.PUBLIC, cm.parseType("void"),

  "sayHello");

  // 生成方法级的 javadoc

  sayHelloMethod.javadoc().add("This method will say Hello to the name.");

  JBlock sayHelloBody = sayHelloMethod.body();

  sayHelloMethod.param(cm.parseType("String"), "name");

  JClass sys = cm.ref("java.lang.System");

  JFieldRef ot = sys.staticRef("out");

  JExpression sentance1 = JExpr.lit("Hello ").invoke("concat").arg(

  JExpr.ref("name"));

  JExpression sentance2 = sentance1.invoke("concat").arg("!");

  sayHelloBody.invoke(ot, "println").arg(sentance2);

  cm.build(destDir);

  }

  public void genTest() throws Exception {

  JCodeModel cm = new JCodeModel();

  File destDir = new File("src");

  JDefinedClass dc = cm._class("dw.sample.singletonTest");

  // 生成类级的 javadoc

  JDocComment jdoc = dc.javadoc();

  jdoc.add("This is the class to test the Singleton class.");

  jdoc.addXdoclet("author Sonia (sxyu@cn.ibm.com)");

  // 生成 main 方法

  JMethod mainMethod = dc.method(JMod.PUBLIC+ JMod.STATIC,

  cm.parseType("void"), "main");

  JBlock mainBody = mainMethod.body();

  mainMethod.param(cm.parseType("String[]"), "args");

  JClass singleton = cm.ref("Singleton");

  JInvocation getIns = singleton.staticInvoke("getInstance");

  mainBody.invoke(getIns, "sayHello").arg(JExpr.lit("CodeModel"));

  cm.build(destDir);

  }

  public static void main(String args[]) {

  SingletonGen sg = new SingletonGen();

  try{

  sg.genSingleton();

  sg.genTest();

  } catch(Exception e) {

  e.printStackTrace();

  }

  }

  }

  运行上述代码将获得两个类 – Singleton 类和 singletonTest 类。

  清单 23. 生成的 Singleton 类

  package dw.sample;

  public class Singleton {

  private static Singleton instance;

  private Singleton() { }

  public static Singleton getInstance() {

  if(instance== null) {

  instance= new Singleton();

  }

  return instance;

  }

  /**

  * This method will say Hello to the name.

  *

  */

  public void sayHello(String name) {

  System.out.println("Hello ".concat(name).concat("!"));

  }

  }

  清单 24. 生成的 singletonTest 类

  package dw.sample;

  /**

  * This is the class to test the Singleton class.

  *

  * @author Sonia (sxyu@cn.ibm.com)

  */

  public class SingletonTest {

  public static void main(String[] args) {

  Singleton.getInstance().sayHello("CodeModel");

  }

  }

  运行 singletonTest 类得到的结果是:

  Hello CodeModel!

  一些大学生经历了就业波折之后,最终选择回炉重塑的大学生们不在少数。在java培训机构(疯狂软件学院http://www.fkjava.org/抢座热线:020-28309358,020-28309378咨询QQ:707552864,544627560 ),教师拥有软件开发经验,在教学中注重实践性,让学员在最短的时间内学到最前沿的编程技术。通过大量全真企业项目训练,让你成为社会急需的软件工程师。通过很短几个月的java培训,学员具备软件开发能力,可以独立进行java软件开发,而且java工程师的薪资在5000元以上,对自己做一个明智的选择,从此改变自己求职时的尴尬境地。