java强制编译时评估

时间:2012-01-03 15:40:57

标签: java bytecode compile-time

在java中,是否有一种强制编译时编译的通用方法?在我参与的编程竞赛中,我们受到机器人在程序运行时可以使用的字节码的限制,所以如果我能够在编译时计算东西,我就有优势。

对于一个具体的例子,假设我想定义一个变量NORTH,它将是一个数组 MapLocations表示机器人面向北方时可以看到的方块。如果我手动编码, 我可以写:

public class SightSensor{
  public static MapLocation[] NORTH = {new MapLocation(-2,2),
                    new MapLocation(-1,1),
                        new MapLocation(-1,2),
                        new MapLocation(0,1),
                        new MapLocation(0,2),
                        new MapLocation(0,3),
                        new MapLocation(1,1),                       
                        new MapLocation(1,2),
                        new MapLocation(2,2)};

}

表示机器人能够在距离为9的距离内看到90度弧内的所有正方形。现在,我的机器人可以看到所有基本方向,有些可以看得更远 相对于其它的。每个可能的代码都是相当繁琐和看似糟糕的形式 视线(距离,方向)对。因此,我写了一个函数

public static MapLocation[] getSensorLocs(int r, Direction dir){ ... bla ... }

自动计算位置,因此我可以将SightSensor类重写为

public class SightSensor{
  public static MapLocation[] NORTH = getSensorLocs(3, Direction.NORTH);
}

唯一的问题是,当机器人试图使用NORTH变量时,它必须花费 是时候运行getSensorLocs方法,因此它比手写版本更昂贵。 我可以强制计算在编译时运行,即在适当的意义上“符号替换”吗?

5 个答案:

答案 0 :(得分:2)

现在我知道您正在优化字节码大小,您可以使用以下方法。

// 8 bytes per field.
public static MapLocation[] NORTH = locations("\u006a\u0079\u007a\u0089\u008a\u008b\u0099\u009a\u009b\u00aa");

// 57 bytes.
public static MapLocation[] locations(String s) {
    final int len = s.length();
    MapLocation[] locations = new MapLocation[len];
    for (int i = 0; i < len; i++) {
        char ch = s.charAt(i);
        locations[i] = new MapLocation((ch >> 4) - 8, (ch & 0xf) - 8);
    }
    return locations;
}

static class MapLocation {
    public MapLocation(int x, int y) {
        System.out.println("x=" + x + ", y=" + y);
    }
}

打印

x=-2, y=2
x=-1, y=1
x=-1, y=2
x=0, y=1
x=0, y=2
x=0, y=3
x=1, y=1
x=1, y=2
x=1, y=3
x=2, y=2

注意:编码String的长度不会添加任何字节代码!。


当您运行第一个代码时,它实际上在运行时创建了数组和每个元素。没有编译时优化。我建议你检查getSensorLocs方法是否以及为什么速度较慢,因为它不应该慢得多。

答案 1 :(得分:1)

public static MapLocation[] NORTH = getSensorLocs(3, Direction.NORTH);已经只评估一次 - 为什么每次都会运行?你已经完成了“预计算”。

我不确定这是否真的是一个评估问题。您似乎想在编译时运行代码,而这通常不是任何语言所做的。 Java没有预处理器,这可能是你所说的最接近的东西。大多数Java都是像计算这样的文字“5 + 3”是“8”。

答案 2 :(得分:1)

这不是你要求的编译时编译 - 它是编译时执行。

你要求的是,在编译时以某种方式计算NORTH,然后将其保存为字节码中的“冻结”值。

这通常不可能或不可取。

如果您受到可以使用的字节码数量的限制,那么请考虑将方向等表示为不是对象,而是作为标志数组。这基本上是用Java编写老式C代码,因此不建议作为一般最佳实践,但在游戏编程中仍然很常见(特别是在Java ME上)

答案 3 :(得分:0)

我相信你能得到的最接近的是编写一个在编译过程中操作代码的注释处理器,就像它在Project Lombok中完成的那样。但这可能是相当多的工作,因为它显然使用javac的非公共API。

答案 4 :(得分:0)

您可以在另一个java项目中编写生成.java文件的代码生成器。您可以重复使用对象(new MapLocation)而不是所有static final MapLocation ML_M2_1 = new MapLocation(-2, 1);},这将有助于更多。唯一能够提高速度的方法是考虑创建查找数据。如果您成功为0xF2创建了new MapLocation(-1, 2)之类的数字编码,那么您确实会保存一些内容。