java内联最终不可变常量

时间:2012-02-28 19:04:54

标签: java unit-testing

是否可以禁止内联最终字符串?可能这是一个奇怪的要求,但我需要在运行时更改最终字段值。这是单元测试的必要条件。

例如:

class asd {
    public static final String value = "sdfmsdkofl";

    public String getValue() {
        return value;
    }
}

我需要以某种方式避免内联value变量。我无法更改源代码:(。这意味着我无法更改字段的访问方式,添加getter和setter。

一些可以关闭ALL优化的神奇参数,即便如此简单。

2 个答案:

答案 0 :(得分:1)

你做不到。唯一可行的解​​决方法是使常量不是final,这使得它不是常数。您应该正在做的是重新组织您的代码,以便可以在没有这种疯狂的情况下进行测试。

答案 1 :(得分:0)

嗯。第一个问题:在生产代码中这是一件坏事。我已经在测试中完成了(切换jdbc驱动程序),但这不是一个好主意。 但是:如果你早做的话,这可能是可行的。 JavaC(假设你使用的是Oracle)没有优化,它都是由JIT完成的。所以,如果你在JIT发挥其魔力之前改变它,那么应该没问题。 理论上,您应该能够在运行时优化之后更改值,因为一旦您更改了字符串,JIT:ed代码应该被标记为不再有效但在这里我确实在非常薄的冰上滑行。 / p>

这是我测试代码的(部分)。

我需要更改此类中的驱动程序:

class MysqlConnection {
   private static final String DRIVER_NAME = "com.mysql.jdbc.Driver";

    protected Connection instantiateNewConnection() {
    try {
        // The newInstance() call is a work around for some 
        // broken Java implementations

        Class.forName(DRIVER_NAME).newInstance();
    } catch (Exception ex) {
        // handle the error 
        LOG.info("Class Exception: " + ex);
    }
}
}

我这样做:

class DBOperation {
    static {
        Field f = MysqlConnection.class.getDeclaredField("DRIVER_NAME");
        f.setAccessible(true);
        f.set(f, LocalFlipper.HSQLDB_DRIVER);
    }
}

这很有效。可以在java中更改最终字段,这不是一个好主意。 首先我修改有问题的字段,然后我实例化一个实例,DRIVET_NAME字段包含我想要的jdbc驱动程序。

似乎有些怀疑这是否有效,但我可以向你保证,为自己尝试一下。

@LouisWasserman:我已经离开了javap:ed部分代码:

Class.forName(DRIVER_NAME).newInstance();

对应

   28:  ldc     #16; //String com.mysql.jdbc.Driver
   30:  invokestatic    #17; //Method  java/lang/Class.forName(Ljava/lang/String;)Ljava/lang/Class;
   33:  invokevirtual   #18; //Method java/lang/Class.newInstance:()Ljava/lang/Object;

如您所见,字符串未内联。此外,如何内联对象(或复杂类型)?您可以自然地内联引用。我同意,如果我们有像

这样的代码
Class.forName("com.mysql.jdbc.Driver");

然后无法访问该字符串,因为我们无法获取它的引用。