2011-02-01 119 views
17

在eclipse中,我对这个findbugs警告有点困惑。在实例方法中写入一个静态变量,为什么这是一个不好的做法?

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"; 
    } 
} 

这是怎么回事有什么不同?为什么是写作从一个实例方法到一个静态变量是一种不好的做法?,我认为它与同步有关,但它仍然不清楚。

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

回答

18

它是一种形式混淆,这可能是违反直觉的。违反直觉的代码阻碍了维护的方便性。

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

让我们重命名doSomethinginitialize

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

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

然而,代码分别为:

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

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

这与通用版本的别名相似,其中同一范围内的两个变量指向相同的实例。


为了您的最后一个例子,

  • 一个实例调用静态方法

    ,一个实例方法是调用静态方法预计不会提高标志的事实。这个例子是有用的,远大于它可能出现的问题。

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

    从某种意义上说,它应该产生一个不同,但类似的警告:即一类与其他类的数据搞乱。但是,通过将静态变量公开为默认的方式,所以这样的警告是不必要的。

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

+1

我喜欢你的理解和清晰度的理解,而不是同步(无论这个方法是否是静态的,这是有问题的)。 – 2011-02-01 23:35:33

1

这是我的,所以带上一粒盐。您提到了同步问题,这是此警告的主要原因,但更重要的是,这两种情况基本上是在不同的概念“数据级”上运行的。实例方法由对象“拥有”并修改描述各个实例的数据。类方法是泛型操作,并声明,虽然与类有关,但与单个对象无关。因此,从每个实例中修改该状态可能(但不一定)是一个糟糕的设计决策。

4

为什么要更改静态字段的用例并不多。 请记住,如果您将此字段设置为该值的所有实例已更改的新值。 这可能会让您在多线程环境中遇到麻烦,其中多个线程正在调用doSomething()。正确的同步是必需的。

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

而且FindBugs的是没有足够的智慧来了解您的实例方法在你的第二个例子:)间接地改变场

0

因为改变一个静态字段会改变它的所有实例,如果没有正确同步,会造成不可预料的问题。

如果您正在阅读属性文件以设置共享字段,请使用静态方法执行此操作。或者,将这些字段重构为一个单独的单例实例,其他类只能读取。如果你只有一个实例,那么使用单例模式并使这些字段是非静态的。

静态方法应该只影响静态数据,而实例方法只应该影响实例数据。

0

我不认为同步(在几个答案中提到)对此有任何影响。毕竟,可以像实例方法一样容易地从多个线程调用静态方法。

这个警告的原因(FindBugs文档没有很好地解释),我想,可以通过几个答案来暗示:它是可疑的,可能是一个错误。就像Jochen Bedersdorfer所说的那样,在另一个实例方法中,你想要在一个类中分配一个静态变量的用例并不是那么多。就像

while (x = y) { 
    // ... 
} 

是不是技术上的错误(实际上是合法的Java,如果X和Y是布尔),它几乎总是错误的。同样,FindBug的作者对这个主题的案例也有同感。

相关问题