Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/unit-testing/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
java内联最终不可变常量_Java_Unit Testing - Fatal编程技术网

java内联最终不可变常量

java内联最终不可变常量,java,unit-testing,Java,Unit Testing,是否可以禁止最终字符串的内联?这可能是一个奇怪的要求,但我需要在运行时更改最终字段值。这对于单元测试是必要的 例如: class asd { public static final String value = "sdfmsdkofl"; public String getValue() { return value; } } 我需要以某种方式避免value变量的内联。并且我不能更改源代码:(。这意味着我不能更改字段的访问方式,添加getter和set

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

例如:

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

    public String getValue() {
        return value;
    }
}
我需要以某种方式避免
value
变量的内联。并且我不能更改源代码:(。这意味着我不能更改字段的访问方式,添加getter和setter


一些神奇的参数会关闭所有的优化,即使是如此简单。

你不能。唯一可能的解决办法是使常量不是最终的,这使得它不是常量。你应该做的是重新组织代码,以便在没有这种疯狂的情况下进行测试。

Hm.First caevat:在生产代码中这样做是不好的。我在测试中做过(切换jdbc驱动程序),但这不是一个好主意。 但是:如果你足够早的话,这可能是可行的。JavaC(假设你使用Oracle的)不进行优化,它都是由JIT来完成的。所以,如果你在JIT发挥其魔力之前更改它,那么它应该是好的。 理论上,您也应该能够在运行时优化之后更改值,因为一旦您更改字符串,JIT:ed代码应该被标记为不再有效,但在这里我确实是如履薄冰

这是我测试代码的一部分

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

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驱动程序

似乎有一些人怀疑这是否有效,但我可以向你们保证,确实有效,你们自己试试吧

@路易斯瓦瑟曼:我已经走了,并对部分代码进行了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");

因为我们无法获取该字符串的引用,所以无法访问该字符串。

这里的理想解决方案是重新组织代码,以便可以在没有这种疯狂的情况下对其进行测试。您是否检查了@Amine是否正确。对于编译时常数
字符串的特殊情况,它完全是重复的,在该问题上讨论的技术正如在该问题的警告中所讨论的那样,这个选项不起作用。你确定它是必要的吗?-如果你解释了为什么需要这样做,并展示了更多的细节,那么也许可以建议一些其他的解决方案…JLS指定常量final字符串始终是内联的。对编译时常量的引用必须在编译时解析为编译时常量值的副本,因此使用此类字段不会导致初始化。"不,它指定它们是内部的,而不是内联的。有关更多信息,请参阅编辑的文章JLS非常清楚地指定,例如,来自另一个类的编译时常量不会导致该类被初始化。Java实现有几种方法可以做到这一点——例如,将常量值复制到另一个类的常量池——但在一个类中使用反射来更改它并不一定会传播。更好的引用:““如果在字段声明中将最终字段初始化为编译时常量,则可能不会观察到对最终字段的更改,因为最终字段的使用在编译时被编译时常量替换。”这似乎非常准确地适用于这里,因为literal
String
满足作为编译时常量的条件。我怀疑JLS可能需要内联常量,这意味着OP的问题没有答案。你能提供一个例子吗?我反汇编了代码,常量已经内联在那里了。