1

我在 java 程序中看到一些非常奇怪的行为。失败是不可重现的,所以我所要做的就是原始日志。

该类看起来像这样:

public class MyClass {
    public static final String MY_CONSTANT_STRING = "This should never change";

    public boolean checkEndsWithCS(String inString) {
        return inString.endsWith(MY_CONSTANT_STRING);
    }

    public String getString() {
        return "Some text '" + MY_CONSTANT_STRING + "' some more text";
    }
}

在日志中,我看到 getString 返回“Some text '' some more text”和 checkEndsWithCS("这些不是您要查找的字符。") 返回 true 的情况。

在这种情况下,我只能得出结论 MY_CONSTANT_STRING 是 "" 。

没有其他类扩展 MyClass,因此它不会在更高级别的类中被覆盖。

我在日志中没有看到任何内存不足的迹象,这似乎是最可能的原因。

它是静态最终的,所以引用不应该改变。字符串是不可变的,所以字符串不应该改变。

问题:

  1. 这些什么时候执行?我在eclipse中设置了一个断点,它永远不会被击中。
  2. 静态最终引用中的不可变字符串是否有任何可能的方法来更改?
  3. 有没有什么可能的方法让字符串不被首先分配?
  4. 是否有任何方式包含字符串或引用的内存可能会被其他对象或进程“破坏”?
  5. 任何其他微妙的陷阱,我只是没有以正确的方式思考这个问题?

如果这里的集体经验不能打破这个松散,那么我只会把它当作我的数据有问题的迹象,并从那个角度检查它。

4

2 回答 2

3

可以使用 Java 反射来更改final字段的值,或者弄乱对象的私有字段String

本机代码(例如native方法)也有可能覆盖内存,这可能会导致某些 String 对象的长度变为零。

如果您的代码库中的某些东西正在做这种事情,那么很难确定罪魁祸首。而且您不应该完全忽略以下可能性:

  • 一些第三方图书馆这样做,
  • 一些不受信任的代码(如果您在没有沙箱的情况下运行不受信任的代码),
  • 利用已知安全漏洞的东西......'因为你没有跟上你的补丁,
  • 某物(或某人)干扰了日志文件。

或者您可能没有运行与您正在查看的源代码匹配的代码。


1)这些何时执行?我在eclipse中设置了一个断点,它永远不会被击中。我在 MY_CONSTANT_STRING ...

该代码作为类的静态初始化的一部分执行。也许它是在你设置断点之前执行的。或者调试器中可能存在错误。

2)静态最终引用中的不可变字符串是否有任何可能的方法来改变?

是的。往上看。

3)有没有什么可能的方法让字符串不被首先分配?

仅给出您在此处编写的代码,不。但是,如果您在静态初始化图中有一个循环,则可以MY_CONSTANT_STRING在分配之前查看 的值。但是,该值将是null......而不是空字符串。

4) 包含字符串或引用的内存有没有可能被其他对象或进程“破坏”?

是的。往上看。

5)任何其他微妙的陷阱,我只是没有以正确的方式思考这个问题?

可能。我无法从这个距离读懂你的想法:-)

于 2013-02-05T09:11:35.327 回答
2

几乎可以肯定,要么:

  1. 这不是您正在执行的实际代码,您的真实代码做了一些有意义的不同的事情,这解释了差异。请您的 IDE 将您带到使用该常量的声明处。可能不是你想的那样。
  2. 这是您的源代码,但编译后的代码不是最新的。看起来你正在执行/不执行你不是/现在的代码
  3. 你实际上并没有调用这个类

static赋值和初始化器发生在类被初始化时,在类的任何方法被调用或实例被创建之前。这是有保证的。String是不可变的,并且final引用在赋值后不会改变。您永远无法覆盖字段,也永远无法覆盖任何静态内容。(尽管您可以肯定地隐藏它们。)

对于该字段,您可能观察到的唯一其他值是null,如果是,final但您在分配它之前在块中引用它时会发生这种情况static——这很难做到,只能在一种循环初始化场景中发生。

除非出现 JVM 错误——而且,这并非完全不可能——任何引用都不会被 Java 代码的任何操作破坏。

于 2013-02-05T09:10:54.603 回答