简体   繁体   English

是否可以在Java中创建任何编译时函数?

[英]Is it possible to create any compile time functions in Java?

I am looking to create some functions in Java that would be called at compile time - and be entirely excluded from the runtime (ie compiled class files). 我正在寻找在Java中创建一些在编译时会被调用的函数-并将它们完全排除在运行时之外(例如,已编译的类文件)。 These functions could write to variables which could have different values for different releases of the software. 这些函数可以写入变量,这些变量对于软件的不同发行版可能具有不同的值。 What's the beast way to do this? 这样做的野兽方法是什么? These could be "final" variables. 这些可能是“最终”变量。

This is, by the way, a GWT project and the functions should be able to write to both client and server sides. 顺便说一下,这是一个GWT项目,这些功能应该能够同时写入客户端和服务器端。

Consider this simple example: 考虑以下简单示例:

final int x = 10;
final int y = x/100;
final int z = y + x - 500;

Here are three "final" variables x, y, and z defined where the values of y and z are dependent on x which is a constant! 这里定义了三个“最终”变量x,y和z,其中y和z的值取决于x,它是一个常数! That means that values of y and z also never actually change in the program. 这意味着y和z的值在程序中也不会实际更改。 But because they have to be defined as a function of x - their values will be calculated at runtime - which is unnecessary usage of resources at runtime. 但是由于必须将它们定义为x的函数-它们的值将在运行时计算-在运行时不必要地使用资源。 A compile time function would hardcode the value of y and z and speed up the runtime by a little bit! 编译时函数将对y和z的值进行硬编码,并加快运行速度! Obviously, this is a simple example but my real use case has plenty of complex time consuming calculations to be done, which slows down my application. 显然,这是一个简单的示例,但是我的实际用例有大量复杂的耗时计算需要完成,这减慢了我的应用程序的速度。 Calculating this at compile time would be really nice and would avoid errors caused by manually hardcoding the numbers if you quickly need multiple releases of the applications with different values of the variables. 如果您很快需要使用变量值不同的多个版本的应用程序,那么在编译时进行计算将非常好,并且可以避免由于手动对数字进行硬编码而导致的错误。

Additionally, consider this example: 此外,请考虑以下示例:

final String value = getMyValue("argument");

final String getMyValue(String variable){
    return variable + "Lol!";
}

Would you expect the value of "value" to be calculated at compile time? 您是否希望在编译时计算“值”的值? On both client and server side? 在客户端和服务器端?

For GWT client side code you can use deferred binding to generate Java code at compile time. 对于GWT客户端代码,您可以在编译时使用延迟绑定来生成Java代码。 You create a subclass of com.google.gwt.core.ext.Generator . 您创建com.google.gwt.core.ext.Generator的子类。 Google uses deferred binding for ie localization, etc. I used it to implement a simple XML mapper for GWT, but that's closed source. Google将延迟绑定用于本地化等。我用它来为GWT实现一个简单的XML映射器,但这是封闭的。

For example you create an interface com.foo.Constants : 例如,您创建一个接口com.foo.Constants

public interface Constants {
  int getY();
  int getZ();
}

And create a Generator for your constants: 并为您的常量创建一个生成器:

public class ConstantsGenerator extends Generator {
  private static final String PACKAGE_NAME = "com.foo";
  private static final String SIMPLE_CLASS_NAME = "GeneratedConstants";
  private static final String CLASS_NAME = PACKAGE_NAME + "." + SIMPLE_CLASS_NAME;

  @Override
  public String generate(TreeLogger logger, GeneratorContext context,
    String typeName) throws UnableToCompleteException {
    // Get a SourceWriter to create the class GeneratedConstants.
    // If it returns null, then this class was already created during this compilation
    // step and we only return the name of class.
    final SourceWriter sourceWriter = getSourceWriter(logger, context);
    if(sourceWriter != null) {
      // Otherwise create the new class ...
      generateConstantsClass(sourceWriter, logger);
    }

    return CLASS_NAME;
  }

  private SourceWriter getSourceWriter(TreeLogger logger, GeneratorContext context) {
    final ClassSourceFileComposerFactory composer = 
      new ClassSourceFileComposerFactory(PACKAGE_NAME, SIMPLE_CLASS_NAME);

    // The generated class implements com.foo.Constants
    composer.addImplementedInterface("com.foo.Constants");

    // Add some imports, if needed
    // composer.addImport("java.util.Map");

    final PrintWriter printWriter = context.tryCreate(logger, PACKAGE_NAME, SIMPLE_CLASS_NAME);
    if(printWriter == null)
      return null;
    else {
      final SourceWriter sw = composer.createSourceWriter(context, printWriter);
      return sw;
    }
  }

  private void generateConstantsClass(SourceWriter sourceWriter, TreeLogger logger) {
    final int y = calculateY();  // Do here the heavy calculation for y.
    final int z = calculateZ();  // Do here the heavy calculation for z.

    // Create the source code for the two Methods getY() and getZ().
    sourceWriter.println(String.format("public int getY() { return %d; }", y));
    sourceWriter.println(String.format("public int getZ() { return %d; }", z));

    sourceWriter.commit(logger);
  }
}

Then you have to configure your GWT module XML file: 然后,您必须配置GWT模块XML文件:

<generate-with class="com.foo.ConstantsGenerator">
  <when-type-assignable class="com.foo.Constants" />
</generate-with>

Then in your GWT client code you can create an instance of your generated class like this: 然后,在您的GWT客户端代码中,您可以创建生成的类的实例,如下所示:

public Constants getConstants() {
  return (Constants) GWT.create(Constants.class);
}

But this only works for client side code. 但这仅适用于客户端代码。 And it is maybe a little bit too much overhead to only precalculate some values. 仅预计算一些值可能会有点过多的开销。

It would be easier to include a code generation step into your build scripts. 将代码生成步骤包括在构建脚本中会更容易。 Then you can use your generated classes both in server and client code. 然后,您可以在服务器和客户端代码中使用生成的类。

But for precalculated values this could still be too much overhead. 但是对于预先计算的值,这仍然可能会产生过多开销。 You can avoid to generate code at all if you only generate a simple file (like a properties file) with your precalculated values and load it at runtime. 如果仅使用预先计算的值生成一个简单文件(如属性文件)并在运行时加载,则可以完全避免生成代码。

On server side this should be no problem. 在服务器端,这应该没问题。 For client side, you can generate your GWT hostpage with JSP and include your precalculated values as a JavaScript dicationary. 对于客户端,您可以使用JSP生成GWT主页,并将预先计算的值包含为JavaScript标记。 In GWT code it is then easy to get access to those values. 在GWT代码中,然后很容易访问这些值。

You are looking for compile time meta programming . 您正在寻找编译时元编程 That means that during compilation phase your source or abstract syntax tree is preprocessed or modified in a certain way. 这意味着在编译阶段,您的源或抽象语法树将以某种方式进行预处理或修改。

If you look at C++, there is template meta programming . 如果您查看C ++,则有模板元编程

As for Java I am not aware of a direct means to accomplish this. 至于Java,我不知道直接实现此目的的方法。

So the next cousin would be Scala : They call it macros , and it allows you to modify the abstract syntax tree at compile time. 因此,下一个表亲将是Scala :它们称其为macros ,它允许您在编译时修改抽象语法树 For example, I use this to remove code completely, based on boolean conditions. 例如,我根据布尔条件使用它完全删除代码。

Given the compatibility, you could write your complex calculations in Scala, and use it from Java. 有了兼容性,您可以在Scala中编写复杂的计算,然后从Java使用它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 是否可以在不使用任何shell的情况下编译和运行Java? - Is it possible to compile and run java without using any shell? 什么时候在编译时或运行时在java中创建字符串池? - when is string pool create in java at compile time or run time? 是否可以创建经过编译时检查的参数化泛型类型? - Is it possible to create compile time checked parametrized generic type? 有什么办法可以在编译时为Java定义一个常量值 - Is there any way to define a constant value to Java at compile time 有没有办法在没有泛型的情况下确保Java在编译时的类型安全 - Is there any way to ensure type safety in java at compile time without generics Java中的任何机制都提供编译时代码变体? - any mechanism in Java to provide compile-time code variants? 是否可以使用spring Java @Configuration避免编译时依赖性? - Is it possible to avoid compile-time dependency using spring Java @Configuration? android java宏还是“编译前替换”可能吗? - android java macros or “before compile time replacements” possible? 是否可以在 Java 的编译时接收子类的名称? - Is it possible to receive subclass's name in compile time in Java? 创建一个bash别名以编译当前目录中的任何.java程序 - Create a bash alias to compile any .java program in the current directory
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM