跳到主要内容

实例

note

要运行这些例子,你需要从GitHub上克隆ActiveJ。

git clone https://github.com/activej/activej

并将其作为一个Maven项目导入。 查看标签 v5.0-beta2。 在运行这些例子之前,先建立项目。 这些例子位于 activej/examples/core/codegen

字节码表达式#

让我们创建一个简单的 sayHello() 方法,打印出 "Hello world!"。 首先,我们将定义一个简单的 例子 接口,它有一个 sayHello() 方法。

public interface Greeter {  void sayHello();}

现在我们可以开始描述 例子 子类行为。 为此目的,我们将使用 ClassBuilder 类。

Class<Greeter> greeterClass = ClassBuilder.create(Greeter.class)    .withMethod("sayHello",        call(staticField(System.class, "out"), "println", value("Hello world")))    .defineClass(CLASS_LOADER);

要实例化描述的类,只需使用 newInstance()

Greeter greeter = greeterClass.getDeclaredConstructor().newInstance();greeter.sayHello();
See full example on GitHub## 动态类的创建 在这个例子中,我们将动态地创建一个实现了一个接口的类。 因此,让我们首先创建一个简单的 **Person** 接口。
@SuppressWarnings("unused")public interface Person extends Comparable<Person> {  void setIdAndName(int id, String name);
  int getId();
  String getName();
  int hashOfPojo(ExamplePojo personPojo);
  int hash();
  @Override  int compareTo(@NotNull Person o);
  @Override  String toString();
  @Override  boolean equals(Object obj);}

继续构建一个实现 Person 接口的类。

// declare fields// setter for both fields - a sequence of actions// compareTo, equals, hashCode and toString methods implementations follow the standard conventionClass<Person> personClass = ClassBuilder.create(Person.class)    // declare fields    .withField("id", int.class)    .withField("name", String.class)
    // setter for both fields - a sequence of actions    .withMethod("setIdAndName", sequence(        set(property(self(), "id"), arg(0)),        set(property(self(), "name"), arg(1))))    .withMethod("getId", property(self(), "id"))    .withMethod("getName", property(self(), "name"))
    // compareTo, equals, hashCode and toString methods implementations follow the standard convention    .withMethod("int compareTo(Person)", compareToImpl("id", "name"))    .withMethod("equals", equalsImpl("id", "name"))    .withMethod("hashOfPojo", hash(property(arg(0), "id"), property(arg(0), "name")))    .withMethod("hash", hash(property(self(), "id"), property(self(), "name")))    .withMethod("toString", ExpressionToString.create()        .withQuotes("{", "}", ", ")        .with("id: ", property(self(), "id"))        .with("name: ", property(self(), "name")))    .defineClass(CLASS_LOADER);

现在我们可以测试我们动态生成的类。

// Instantiate two objects of dynamically defined classPerson jack = personClass.getDeclaredConstructor().newInstance();Person martha = personClass.getDeclaredConstructor().newInstance();
jack.setIdAndName(5, "Jack");martha.setIdAndName(jack.getId() * 2, "Martha");
System.out.println("First person: " + jack);System.out.println("Second person: " + martha);
System.out.println("jack.equals(martha) ? : " + jack.equals(martha));
See full example on GitHub## 计算器实例 在这个例子中,我们将创建一个计算器,将输入的方程式字符串解析为AST。 然后,它生成了一个 优化的类来计算表达式。 首先,创建一个解析器,返回表达式的AST。
// Instantiate two objects of dynamically defined classPerson jack = personClass.getDeclaredConstructor().newInstance();Person martha = personClass.getDeclaredConstructor().newInstance();
jack.setIdAndName(5, "Jack");martha.setIdAndName(jack.getId() * 2, "Martha");
System.out.println("First person: " + jack);System.out.println("Second person: " + martha);
System.out.println("jack.equals(martha) ? : " + jack.equals(martha));

接下来,创建一个 ClassBuilder ,描述将被生成的类。 它将实现 DoubleUnaryOperator 接口,并将有一个 applyAsDouble 方法。 让我们来创建相应的构建器。

public static Class<DoubleUnaryOperator> compile(String expression) {  return ClassBuilder.create(DoubleUnaryOperator.class)      .withMethod("applyAsDouble", PARSER.parse(expression))      .defineClass(CLASS_LOADER);}

该方法将有一个 var1 参数,用于未知 x

private static final Parser<Expression> UNKNOWN = DELIMITERS.token("x").retn(Expressions.arg(0))。

因此,ActiveJ Codegen将生成以下类别的字节码。

public final class Class1 implements DoubleUnaryOperator {    public Class1() {    }
    public double applyAsDouble(double var1) {        return (2.0D 2.0D * 2.0D) * -var1 5.0D 1024.0D / (100.0D 58.0D) * 50.0D * 37.0D - 100.0D 2.0D * Math.pow(var1, 2.0D) .0D;    }}

现在让我们来处理一下手工编写的代码和动态生成的实例评估。

public static void main(String[] args) throws Exception {  double x = -1;
  // manual code, super fast  System.out.println(((2.0 + 2.0 * 2.0) * -x) + 5.0 + 1024.0 / (100.0 + 58.0) * 50.0 * 37.0 - 100.0 + 2.0 * Math.pow(x, 2.0) % 3.0);
  DoubleUnaryOperator instance = compile("((2 + 2 * 2) * -x) + 5 + 1024 / (100 + 58) * 50 * 37 - 100 + 2 * x ^ 2 % 3").getDeclaredConstructor().newInstance();
  // generated instance evaluation, literally equivalent to manual code (with a method call around it), except it was dynamically generated  System.out.println(instance.applyAsDouble(x));}

我们还对这个表达式进行了基准测试,以比较其性能。

基准模式 Cnt得分 误差单位CalculatorBenchmark.generated avgt 10 115.882 ± 1.082 ns/opCalculatorBenchmark.manual avgt 10 115.222 ± 1.600 ns/op

你可以在以下网站上找到实例来源 GitHub