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实现有几种方法可以做到这一点——例如,将常量值复制到另一个类的常量池——但在一个类中使用反射来更改它并不一定会传播。更好的引用:““如果在字段声明中将最终字段初始化为编译时常量,则可能不会观察到对最终字段的更改,因为最终字段的使用在编译时被编译时常量替换。”这似乎非常准确地适用于这里,因为literalString
满足作为编译时常量的条件。我怀疑JLS可能需要内联常量,这意味着OP的问题没有答案。你能提供一个例子吗?我反汇编了代码,常量已经内联在那里了。