项目概况

APT技术

2026-01-299 min read后端技术
字节码增强

一、什么是APT

APT(Annotation Processing Tool) 注解处理器,是 javac 的一个工具,他可以在源码生成class的时候,处理Java语法树。 我们用他可以干什么呢?

  1. lombok的原理,在编译期修改字节码,生成 getset 方法。

本文我们就使用APT技术, 来自动生成get和set方法

源码地址

感兴趣的可以了解一下,不用害怕,尤其是2.6到2.7目录,不需要看到这个API就害怕。也不用死记硬背。了解就好。 正经人是不会用这个生成字节码的,字节码生成我们有很多好用的工具。

  • [Javassist]

或者是 javapoet

二、实战演示

2.1 定义处理器

继承 AbstractProcessor

java
1@AutoService(Processor.class) 2@SupportedAnnotationTypes({"cn.lxchinesszz.MyData","cn.lxchinesszz.MyGetter","cn.lxchinesszz.MySetter"}) 3// 这个注解处理器是处理哪个注解的 4@SupportedSourceVersion(SourceVersion.RELEASE_8) 5public class MyLombokProcessor extends AbstractProcessor { 6 7 @Override 8 public synchronized void init(ProcessingEnvironment processingEnvironment) {} 9 10 @Override 11 public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnv) {} 12}
  • @AutoService 谷歌提供的SPI工具。当使用这个注解会自定生成Java SPI文件, 当然如果不想用谷歌的工具,我们也可以自己来写配置文件
text
1├── classes 2│   ├── META-INF 3│   │   └── services 4│   │   └── javax.annotation.processing.Processor
  • @SupportedAnnotationTypes({"cn.lxchinesszz.MyData","cn.lxchinesszz.MyGetter","cn.lxchinesszz.MySetter"})

支持的注解类型

  • @SupportedSourceVersion(SourceVersion.RELEASE_8)

支持的源码类型

2.2 Element 体系

  • roundEnv.getElementsAnnotatedWith(MyData.class) 可以获取被该注解修饰的类或者字段或者方法。

下面我们看下 Element 的类型。

java
1public class User{ // TypeElement 2 3 private String name; // VariableElement 4 5 private Interge age; // VariableElement 6 7 public String getName(){ // ExecutableElement 8 return this.name; 9 } 10 11 public void setName( // ExecutableElement 12 String name // VariableElement 13 ){ 14 this.name = name; 15 } 16}

如何知道Element 的类型呢。

  • Element#getKind

2.2.1 获取字段信息

这里我们先自定义一个字段类型来获取基础信息,来学习 Element

java
1 public class FieldElement extends ModifierElement { 2 3 /** 4 * 字段名 5 */ 6 private final String fieldName; 7 8 /** 9 * 字段类型 10 */ 11 private Class<?> fieldType; 12 13 /** 14 * 资源原始类型 15 */ 16 private final VariableElement fieldElement; 17 18 /** 19 * 基本类型提示 20 */ 21 private String remark; 22 23 /** 24 * 字段所属类 25 */ 26 private final TypeElement classElement; 27 28 public FieldElement(String fieldName, VariableElement fieldElement) { 29 super(fieldElement); 30 this.fieldName = fieldName; 31 this.fieldElement = fieldElement; 32 this.classElement = (TypeElement) fieldElement.getEnclosingElement(); 33 try { 34 if (isPrimitive()) { 35 fieldType = null; 36 this.remark = "基本类型:" + fieldElement.asType().toString(); 37 } else { 38 this.fieldType = Class.forName(fieldElement.asType().toString()); 39 } 40 } catch (ClassNotFoundException e) { 41 // 如果还报错说明是一个泛型 根据泛型类型来进行处理 fieldElement.asType() 42 // DeclaredType Set<String> 43 // WildcardType 44 // ? 45 // ? extends Number 46 // ? super T 47 this.fieldType = Object.class; 48 } 49 } 50 }
  • 首先先判断是字段类型
java
1 public static FieldElement toFiledElement(Element enclosedElement) { 2 if (ElementKind.FIELD.equals(enclosedElement.getKind())) { 3 VariableElement fieldElement = (VariableElement) enclosedElement; 4 Name simpleName = fieldElement.getSimpleName(); 5 return new FieldElement(simpleName.toString(), fieldElement); 6 } else { 7 throw new RuntimeException("enclosedElement 不是字段类型:" + enclosedElement); 8 } 9 } 10

2.2.1 获取方法信息

  • 方法包括方法参数和返回值,这里我们自定义一个方法参数。
java
1public class MethodElement extends ModifierElement{ 2 3 /** 4 * 方法参数名 5 */ 6 private final String methodName; 7 8 /** 9 * 返回值 10 */ 11 private Class<?> returnType; 12 13 /** 14 * 方法原始信息 15 */ 16 private final ExecutableElement methodElement; 17 18 /** 19 * 方法参数 20 */ 21 private final List<MethodParamElement> methodParamElements; 22 23 public MethodElement(ExecutableElement methodElement, List<MethodParamElement> methodParamElements) { 24 super(methodElement); 25 this.methodName = methodElement.getSimpleName().toString(); 26 try { 27 TypeMirror returnTypeMirror = methodElement.getReturnType(); 28 if (returnTypeMirror instanceof NoType) { 29 this.returnType = Void.TYPE; 30 } else { 31 this.returnType = Class.forName(methodElement.getReturnType().toString()); 32 } 33 } catch (ClassNotFoundException e) { 34 this.returnType = Void.TYPE; 35 } 36 this.methodElement = methodElement; 37 this.methodParamElements = methodParamElements; 38 } 39}
  • 生成方法
java
1 public static MethodParamElement toMethodParamElement(Element enclosedElement) { 2 if (ElementKind.PARAMETER.equals(enclosedElement.getKind())) { 3 VariableElement fieldElement = (VariableElement) enclosedElement; 4 Name simpleName = fieldElement.getSimpleName(); 5 return new MethodParamElement(simpleName.toString(), fieldElement); 6 } else { 7 throw new RuntimeException("enclosedElement 不是字段类型:" + enclosedElement); 8 } 9 } 10 11 public static MethodElement toMethodElement(Element enclosedElement) { 12 if (ElementKind.METHOD.equals(enclosedElement.getKind())) { 13 ExecutableElement methodElement = (ExecutableElement) enclosedElement; 14 List<? extends VariableElement> parameters = methodElement.getParameters(); 15 List<MethodParamElement> paramElements = new ArrayList<>(); 16 for (VariableElement parameter : parameters) { 17 paramElements.add(toMethodParamElement(parameter)); 18 } 19 return new MethodElement(methodElement, paramElements); 20 } else { 21 throw new RuntimeException("enclosedElement 不是方法类型:" + enclosedElement.getClass()); 22 } 23 }

2.2.2 获取类信息

类信息包括字段和方法

java
1public class ClassElement extends ModifierElement { 2 3 /** 4 * 类名称 5 */ 6 private final String className; 7 8 /** 9 * 包名称 10 */ 11 private final String packageName; 12 13 /** 14 * 类原始信息 15 */ 16 private final TypeElement classElement; 17 18 /** 19 * 字段信息 20 */ 21 private final List<FieldElement> fieldElements; 22 23 /** 24 * 方法信息 25 */ 26 private final List<MethodElement> methodElements; 27 28 public ClassElement(Element enclosedElement, List<FieldElement> fieldElements, List<MethodElement> methodElements) { 29 super(enclosedElement); 30 this.classElement = (TypeElement) enclosedElement; 31 this.fieldElements = fieldElements; 32 this.methodElements = methodElements; 33 this.className = classElement.getSimpleName().toString(); 34 this.packageName = classElement.getQualifiedName().toString().replaceAll("." + classElement.getSimpleName().toString(), ""); 35 } 36}

生成类信息

java
1public static ClassElement toClassElement(Element enclosedElement) { 2 if (ElementKind.CLASS.equals(enclosedElement.getKind())) { 3 List<? extends Element> enclosedElements = enclosedElement.getEnclosedElements(); 4 List<FieldElement> fieldElements = new ArrayList<>(); 5 List<MethodElement> methodElements = new ArrayList<>(); 6 for (Element element : enclosedElements) { 7 if (ElementKind.FIELD.equals(element.getKind())) { 8 fieldElements.add(toFiledElement(element)); 9 } 10 if (ElementKind.METHOD.equals(element.getKind())) { 11 methodElements.add(toMethodElement(element)); 12 } 13 } 14 return new ClassElement(enclosedElement, fieldElements, methodElements); 15 } else { 16 throw new RuntimeException("enclosedElement 不是字段类型:" + enclosedElement); 17 } 18} 19

2.3 日志打印

APT方法中日志的打印,要使用工具。在初始化方法中获取消息打印实例。

java
1public class MyLombokProcessor extends AbstractProcessor { 2 private Messager message; 3 4 @Override 5 public synchronized void init(ProcessingEnvironment processingEnvironment) { 6 super.init(processingEnvironment); 7 message = processingEnvironment.getMessager(); 8 } 9 10 @Override 11 public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnv) { 12 // 扫描所有被@MyData注解的元素 13 processingEnv.getMessager().printMessage(NOTE, "------------MyData-----------" + roundEnv.getElementsAnnotatedWith(MyData.class)); 14 } 15}

就想log日志一样,他也是有消息类型的,如: 提示、异常、警告等。如下枚举

java
1/** 2 * 诊断类型,例如错误或警告。诊断的类型可用于确定应如何将诊断呈现给用户。例如,错误可能被涂成红色或以“错误”一词为前缀, 3 * 而警告可能被涂成黄色或以“警告”一词为前缀。没有要求 Kind 应该对诊断消息暗示任何固有的语义含义:例如,一个工具可能会 4 * 提供一个选项来将所有警告报告为错误。 5 */ 6enum Kind { 7 /** 8 * 阻止工具正常完成编译 9 */ 10 ERROR, 11 /** 12 * 警告 13 */ 14 WARNING, 15 /** 16 * 类似于警告的问题,但由工具规范强制要求。例如,Java™ 语言规范要求对某些未经检查的操作和使用过时的方法发出警告。 17 */ 18 MANDATORY_WARNING, 19 /** 20 * 来自该工具的信息性消息。 21 */ 22 NOTE, 23 /** 24 * 其他类型的诊断 25 */ 26 OTHER, 27 }

2.4 字节码修改

字节码修改首先我们要拿到字节码语法树对象,通过观察者模式类进行修改。这里也在初始化时候获取工具。 如下我们先定义一个工具。

java
1public class ClassElementBuilder { 2 3 private ProcessingEnvironment processingEnv; 4 5 private JavacTrees trees; 6 7 protected Names names; 8 9 protected TreeMaker treeMaker; 10 11 12 public ClassElementBuilder(ProcessingEnvironment processingEnv) { 13 Context context = ((JavacProcessingEnvironment) processingEnv).getContext(); 14 this.processingEnv = processingEnv; 15 this.trees = JavacTrees.instance(processingEnv); 16 this.treeMaker = TreeMaker.instance(context); 17 this.names = Names.instance(context); 18 } 19}

处理器初始化方法进行工具的实例化。

java
1 @Override 2 public synchronized void init(ProcessingEnvironment processingEnvironment) { 3 super.init(processingEnvironment); 4 this.classElementBuilder = new ClassElementBuilder(processingEnvironment); 5 }

此时我们就能对添加和修改语法树了。但是这里我们先不着急, 我们在先学习一下语法树的API。

2.5 JCTree 语法树

2.5.1 定义字段

定义变量使用

  • TreeMaker#VarDef(JCTree.JCModifiers 字段修饰符,Names 字段名,JCExpression 字段类型,JCExpression 赋值语句)
java
1private String ${fieldName}; 2private JCTree.JCVariableDecl generateStringField(JCTree.JCClassDecl jcClassDecl, String fieldName) { 3 JCTree.JCVariableDecl var = treeMaker.VarDef( 4 treeMaker.Modifiers(Flags.PRIVATE), 5 names.fromString(fieldName), 6 treeMaker.Ident(names.fromString("String")), 7 null); 8 jcClassDecl.defs = jcClassDecl.defs.prepend(var); 9 return var; 10} 11 12private String ${fieldName} = ${fieldName} 13private JCTree.JCVariableDecl generateStringField(JCTree.JCClassDecl jcClassDecl, String fieldName) { 14 // 字段的赋值语句 15 JCTree.JCVariableDecl var = treeMaker.VarDef( 16 treeMaker.Modifiers(Flags.PRIVATE), 17 names.fromString(fieldName), 18 treeMaker.Ident(names.fromString("String")), 19 treeMaker.Literal(fieldName)); 20 21 jcClassDecl.defs = jcClassDecl.defs.prepend(var); 22 return var; 23}

要想理解这个API,实现要分析字段是由什么构成的,正如下图。

标示符三种处理方式。

  1. 包装类型,不用引入包,可以直接使用
  • TreeMaker#Ident JCExpression
java
1treeMaker.Ident(names.fromString("String"))
  1. 基本类型,不用引入包,可以直接使用
  • TreeMaker#TypeIdent
java
1treeMaker.TypeIdent(TypeTag.INT)
  1. 引用类型,需要引入包后再直接使用
  • 先引入包,然后就向包装类型那样进行处理。
java
1// import package 2private JCTree.JCImport genImportPkg(String packageName, String className) { 3 JCTree.JCIdent ident = treeMaker.Ident(names.fromString(packageName)); 4 return treeMaker.Import(treeMaker.Select( 5 ident, names.fromString(className)), false); 6}

2.5.2 定义get和set方法

生成set方法,方法是由

  • 方法修饰符 treeMaker.Modifiers(Flags.PUBLIC + Flags.STATIC + Flags.FINAL)
  • 方法名 names.fromString("setName")
  • 方法返回值 treeMaker#Type、treeMaker#TypeIdent
java
1/** 2 * public void setName(String name){ 3 * this.name = name; 4 * } 5 * 6 * @param jcClassDecl7 * @param f 字段 8 * @param fieldName 字段名 9 */ 10private void generateSetMethod(JCTree.JCClassDecl jcClassDecl, JCTree.JCVariableDecl f, String fieldName) { 11 // 方法体内容 12 ListBuffer<JCTree.JCStatement> statements = new ListBuffer<>(); 13 // this.MyDate 14 JCTree.JCFieldAccess aThis = treeMaker.Select(treeMaker.Ident(names.fromString("this")), names.fromString(fieldName)); 15 // this.MyDate = MyDate; 16 JCTree.JCExpressionStatement exec = treeMaker.Exec(treeMaker.Assign(aThis, treeMaker.Ident(names.fromString(fieldName)))); 17 statements.add(exec); 18 JCTree.JCBlock body = treeMaker.Block(0, statements.toList()); 19 20 // 方法参数 21 JCTree.JCVariableDecl param = treeMaker.VarDef(treeMaker.Modifiers(Flags.PARAMETER), names.fromString(fieldName), f.vartype, null); 22 com.sun.tools.javac.util.List<JCTree.JCVariableDecl> parameters = com.sun.tools.javac.util.List.of(param); 23 24 JCTree.JCMethodDecl getNameMethod = treeMaker.MethodDef( 25 treeMaker.Modifiers(Flags.PUBLIC), // 方法修饰符 26 names.fromString("set" + capRename(fieldName)), // 方法名,capName转驼峰 27 treeMaker.Type(new Type.JCVoidType()), // 方法返回值类型 28 List.nil(), 29 parameters, // 方法参数 30 List.nil(), 31 body,// 方法体 32 null 33 ); 34 // 插入到语法树中 35 jcClassDecl.defs = jcClassDecl.defs.prepend(getNameMethod); 36} 37 38/** 39 * public void getName(){ 40 * return this.name; 41 * } 42 * 43 * @param jcClassDecl44 * @param f 字段 45 * @param fieldName 字段名 46 */ 47private void generateGetMethod(JCTree.JCClassDecl jcClassDecl, JCTree.JCVariableDecl f, String fieldName) { 48 // 方法体内容 49 ListBuffer<JCTree.JCStatement> statements = new ListBuffer<>(); 50 // this.name 51 JCTree.JCFieldAccess select = treeMaker.Select(treeMaker.Ident(names.fromString("this")), 52 names.fromString(fieldName)); 53 // 生成return代码 return this.name 54 JCTree.JCReturn jcReturn = treeMaker.Return(select); 55 statements.add(jcReturn); 56 // 方法体 57 JCTree.JCBlock body = treeMaker.Block(0, statements.toList()); 58 // 生成方法 59 JCTree.JCMethodDecl getNameMethod = treeMaker.MethodDef( 60 treeMaker.Modifiers(Flags.PUBLIC), // 方法修饰符 61 names.fromString("get" + capRename(fieldName)), // 方法名 62 f.vartype, // 方法返回值类型 63 List.nil(), 64 List.nil(), // 方法参数 65 List.nil(), 66 body, // 方法体 67 null 68 ); 69 // 插入到语法树中 70 jcClassDecl.defs = jcClassDecl.defs.prepend(getNameMethod); 71}

参考文章

2.6 TreeMaker

部分内容翻译自

2.6.1 Modifiers 修饰符

java中类,方法,字段都是有修饰符的。

java
1public JCModifiers Modifiers(long flags) { 2 return Modifiers(flags, List.< JCAnnotation >nil()); 3} 4 5public JCModifiers Modifiers(long flags, 6 List<JCAnnotation> annotations) { 7 JCModifiers tree = new JCModifiers(flags, annotations); 8 boolean noFlags = (flags & (Flags.ModifierFlags | Flags.ANNOTATION)) == 0; 9 tree.pos = (noFlags && annotations.isEmpty()) ? Position.NOPOS : pos; 10 return tree; 11}
  • 定义多个修饰符

treeMaker.Modifiers(Flags.PUBLIC + Flags.STATIC + Flags.FINAL);

2.6.2 ClassDef 定义类

java
1 2public JCClassDecl ClassDef(JCModifiers mods, // 访问标志,可以通过 TreeMaker.Modifiers 来创建 3 Name name, // 类名 4 List<JCTypeParameter> typarams, // 泛型参数列表 5 JCExpression extending, // 父类 6 List<JCExpression> implementing, // 实现的接口 7 List<JCTree> defs) { // 类定义的详细语句,包括字段、方法的定义等等 8 JCClassDecl tree = new JCClassDecl(mods, 9 name, 10 typarams, 11 extending, 12 implementing, 13 defs, 14 null); 15 tree.pos = pos; 16 return tree; 17}

2.6.3 MethodDef 定义方法

java
1public JCMethodDecl MethodDef(JCModifiers mods, // mods:访问标志 2 Name name, // 方法名 3 JCExpression restype, // 返回类型,返回类型 restype 填写 null 或者 treeMaker.TypeIdent(TypeTag.VOID) 都代表返回 void 类型 4 List<JCTypeParameter> typarams, // 泛型参数列表 5 List<JCVariableDecl> params, // 参数列表 6 List<JCExpression> thrown, // 异常声明列表 7 JCBlock body, // 方法体 8 JCExpression defaultValue // 默认方法(可能是 interface 中的哪个 default) 9 ) { 10 JCMethodDecl tree = new JCMethodDecl(mods, 11 name, 12 restype, 13 typarams, 14 params, 15 thrown, 16 body, 17 defaultValue, 18 null); 19 tree.pos = pos; 20 return tree; 21} 22

2.6.4 VarDef 定义字段

java
1public JCVariableDecl VarDef(JCModifiers mods, // 访问标志 2 Name name, // 参数名称 3 JCExpression vartype, // 类型 4 JCExpression init // 初始化语句 5 ) { 6 JCVariableDecl tree = new JCVariableDecl(mods, name, vartype, init, null); 7 tree.pos = pos; 8 return tree; 9} 10 11public JCVariableDecl VarDef(VarSymbol v, 12 JCExpression init) { 13 return (JCVariableDecl) 14 new JCVariableDecl( 15 Modifiers(v.flags(), Annotations(v.getAnnotationMirrors())), 16 v.name, 17 Type(v.type), 18 init, 19 v).setPos(pos).setType(v.type); 20}

2.6.5 Return 定义返回

java
1public JCReturn Return(JCExpression expr) { 2 JCReturn tree = new JCReturn(expr); 3 tree.pos = pos; 4 return tree; 5}

2.6.6 Ident 定义关键字

  • treeMaker.Ident(names.fromString("this"))
java
1public JCIdent Ident(Name name) { 2 JCIdent tree = new JCIdent(name, null); 3 tree.pos = pos; 4 return tree; 5} 6 7public JCIdent Ident(Symbol sym) { 8 return (JCIdent)new JCIdent((sym.name != names.empty) 9 ? sym.name 10 : sym.flatName(), sym) 11 .setPos(pos) 12 .setType(sym.type); 13} 14 15public JCExpression Ident(JCVariableDecl param) { 16 return Ident(param.sym); 17}

2.6.7 Select

TreeMaker.Select 用于创建域访问 / 方法访问

java
1public JCFieldAccess Select(JCExpression selected, 2 Name selector) 3{ 4 JCFieldAccess tree = new JCFieldAccess(selected, selector, null); 5 tree.pos = pos; 6 return tree; 7} 8 9public JCExpression Select(JCExpression base, 10 Symbol sym) { 11 return new JCFieldAccess(base, sym.name, sym).setPos(pos).setType(sym.type); 12}

两个参数第一个是对象,第二个是对象的那个方法。

  • this.${fieldName}
java
1 JCTree.JCFieldAccess aThis = treeMaker.Select(treeMaker.Ident(names.fromString("this")), names.fromString(fieldName));

2.6.8 NewClass

用于创建 new 语句语法树节点(JCNewClass)

java
1public JCNewClass NewClass(JCExpression encl, 2 List<JCExpression> typeargs, // 参数类型列表 3 JCExpression clazz, // 待创建对象的类型 4 List<JCExpression> args, // 参数列表 5 JCClassDecl def) { // 类定义 6 JCNewClass tree = new JCNewClass(encl, typeargs, clazz, args, def); 7 tree.pos = pos; 8 return tree; 9}

2.6.9 Assign 赋值语句

类似 Select, 如果说Select是 . 那么Assign是 =

java
1public JCAssign Assign(JCExpression lhs, 2 JCExpression rhs) { 3 JCAssign tree = new JCAssign(lhs, rhs); 4 tree.pos = pos; 5 return tree; 6}

select和assign配合使用

java
1 // this.MyDate 2 JCTree.JCFieldAccess aThis = treeMaker.Select(treeMaker.Ident(names.fromString("this")), names.fromString(fieldName)); 3 // this.MyDate = MyDate; 4 JCTree.JCExpressionStatement exec = treeMaker.Exec(treeMaker.Assign(aThis, treeMaker.Ident(names.fromString(fieldName)))); 5

2.6.10 Exec执行语句

配合赋值语句使用

java
1public JCExpressionStatement Exec(JCExpression expr) { 2 JCExpressionStatement tree = new JCExpressionStatement(expr); 3 tree.pos = pos; 4 return tree; 5} 6

2.6.11 Apply 方法调用

java
1// 创建一个方法调用 user.say("hello world!"); 2JCTree.JCExpressionStatement exec2 = treeMaker.Exec( 3 treeMaker.Apply( 4 com.sun.tools.javac.util.List.nil(), 5 treeMaker.Select( 6 treeMaker.Ident(names.fromString("user")), // . 左边的内容 7 names.fromString("say") // . 右边的内容 8 ), 9 com.sun.tools.javac.util.List.of(treeMaker.Literal("hello world!")) // 方法中的内容 10 ) 11);

2.7 代码片段

2.6的API,是真的难用,这里列几个片段。

2.7.1 生成字段

  • private String age;
java
1// 生成参数 例如:private String age; 2treeMaker.VarDef(treeMaker.Modifiers(Flags.PRIVATE), names.fromString("age"), treeMaker.Ident(names.fromString("String")), null);

2.7.2 赋值变量

  • private String name = "西魏陶渊明"
java
1treeMaker.VarDef(treeMaker.Modifiers(Flags.PRIVATE),names.fromString("name"),treeMaker.Ident(names.fromString("String")),treeMaker.Literal("西魏陶渊明")) 2

2.7.3 相加

  • JCTree.Tag.PLUS
java
1treeMaker.Exec(treeMaker.Assign(treeMaker.Ident(names.fromString("add")),treeMaker.Binary(JCTree.Tag.PLUS,treeMaker.Literal("a"),treeMaker.Literal("b"))))

2.7.4 += 语法

  • JCTree.Tag.PLUS_ASG
java
1treeMaker.Exec(treeMaker.Assignop(JCTree.Tag.PLUS_ASG, treeMaker.Ident(names.fromString("add")), 2treeMaker.Literal("test")))

2.7.5 ++ 语法

java
1treeMaker.Exec(treeMaker.Unary(JCTree.Tag.PREINC,treeMaker.Ident(names.fromString("i"))))

2.7.6 If语句

java
1/* 2 创建一个if语句 3 if("BuXueWuShu".equals(name)){ 4 add = "a" + "b"; 5 }else{ 6 add += "test"; 7 } 8 */ 9// "BuXueWuShu".equals(name) 10JCTree.JCMethodInvocation apply = treeMaker.Apply( 11 com.sun.tools.javac.util.List.nil(), 12 treeMaker.Select( 13 treeMaker.Literal("BuXueWuShu"), // . 左边的内容 14 names.fromString("equals") // . 右边的内容 15 ), 16 com.sun.tools.javac.util.List.of(treeMaker.Ident(names.fromString("name"))) 17); 18// add = "a" + "b" 19JCTree.JCExpressionStatement exec3 = treeMaker.Exec(treeMaker.Assign(treeMaker.Ident(names.fromString("add")), treeMaker.Binary(JCTree.Tag.PLUS, treeMaker.Literal("a"), treeMaker.Literal("b")))); 20// add += "test" 21JCTree.JCExpressionStatement exec1 = treeMaker.Exec(treeMaker.Assignop(JCTree.Tag.PLUS_ASG, treeMaker.Ident(names.fromString("add")), treeMaker.Literal("test"))); 22 23JCTree.JCIf anIf = treeMaker.If( 24 apply, // if语句里面的判断语句 25 exec3, // 条件成立的语句 26 exec1 // 条件不成立的语句 27); 28