在实例方法中写入静态变量,为什么这是一个不好的做法?

2022-09-03 01:09:19

我在这里对日食中的这个发现虫警告有点困惑。

public class MyClass {
    public static String myString;
}


public class AnotherClass {
   public void doSomething() {
       MyClass.myString = "something";
   }
}

这给了我一个findbugs警告“从实例方法写入静态字段”,但是这并没有给我一个警告:

public class MyClass {
    public static String myString;
}


public class AnotherClass {
   public void doSomething() {
       doAnotherThing();
   }
   public static doAnotherThing() {
       MyClass.myString = "something";
   }
}

这有什么不同?,为什么从实例方法写入静态变量是一种不好的做法?,我假设它与同步有关,但我仍然不清楚。

我知道这看起来变量应该是最终的,但我正在从属性文件加载值。


答案 1

它是一种混叠形式,可能违反直觉。违反直觉的代码妨碍了维护的便利性。

从逻辑上讲,我们希望实例方法会影响该实例的数据。我们预计静态方法会影响静态数据。

让我们重命名为:doSomethinginitialize

...
a.initialize();
...
b.initialize();
...

此代码的读者可能不会立即意识到 和 的实例实际上正在影响相同的数据。这可能是一个错误,因为我们初始化了两次相同的内存,但它并不明显,因为我们可能需要调用每个实例似乎是合理的。abinitialize

但是,代码是:

...
MyClass.initialize();
...
MyClass.initialize();
...

在这种情况下,更直观的是,我们可能会影响相同的静态数据,这可能是一个错误。

这类似于别名的常见版本,其中同一作用域中的两个变量指向同一实例。


对于最后一个示例,

  • 实例调用静态方法

    实例方法调用静态方法的事实不应引起标志。例如,这很有用,远远超过了它可能是一个问题的地方。

  • 一个类的静态方法会影响另一个类的静态数据

    从某种意义上说,它应该生成一个不同但类似的警告:一个类正在弄乱另一个类的数据。但是,通过公开静态变量是默认批准这一点的一种方式,因此不需要这样的警告。

请记住,FindBugs只是试图在代码中标记潜在的可能问题,而不是每个可能的问题。您的第一个示例可能是一个潜在的维护问题,您需要检查它是否是一个真正的问题。你的第二个示例可能不是问题,或者它是一个真正的问题,与它不是问题的用例过于相似。


答案 2

对于为什么要更改静态字段,没有太多用例。请记住,如果将此字段设置为新值,则该值已针对此类的所有实例进行了更改。这可能会让您在多线程环境中遇到麻烦,其中多个线程正在调用 。需要适当的同步。doSomething()

在 99% 的情况下,您希望实例方法仅更改非静态字段,这就是 findbugs 警告您的原因。

而且 findbugs 不够聪明,无法了解您的实例方法间接更改了第二个示例中的字段:)


推荐