在实例方法中写入静态变量,为什么这是一个不好的做法?
我对 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";
}
}
这有什么不同?以及为什么从实例方法写入静态变量是一个不好的做法?,我假设它与同步有关,但我仍然不清楚。
我知道这看起来变量应该是最终的,但我正在从属性文件加载值。
I am a little confused here with this findbugs warning in eclipse.
public class MyClass {
public static String myString;
}
public class AnotherClass {
public void doSomething() {
MyClass.myString = "something";
}
}
This gives me a findbugs warning "write to static field from instance method", however this does not give me a warning:
public class MyClass {
public static String myString;
}
public class AnotherClass {
public void doSomething() {
doAnotherThing();
}
public static doAnotherThing() {
MyClass.myString = "something";
}
}
How is this any different?, and why is writing to a static variable from an instance method a bad practice?, I assume it has to do with synchronization, but it is still not clear to me.
I know this looks like the variable should be final, but I am loading the value from a properties file.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
它是一种别名形式,可能违反直觉。反直觉的代码妨碍了维护的方便性。
从逻辑上讲,我们期望实例方法会影响该实例的数据。我们期望静态方法会影响静态数据。
让我们将
doSomething
重命名为initialize
:此代码的读者可能不会立即意识到
a
和b
的实例实际上影响相同的数据。这可能是一个错误,因为我们两次初始化相同的内存,但它并不明显,因为我们可能需要在每个实例上调用initialize
似乎是合理的。然而,代码是:
在这种情况下,更直观的是我们可能会影响相同的静态数据,这可能是一个错误。
这类似于别名的常见版本,其中同一范围内的两个变量指向同一实例。
对于最后一个示例,
实例调用静态方法
实例方法调用静态方法的事实预计不会引发标志。这些例子表明,它的用处远远超过了它可能出现的问题。
一个类的静态方法会影响另一个类的静态数据
从某种意义上说,它应该生成一个不同但相似的警告:一个类正在弄乱另一个类的数据。然而,通过将静态变量设为 public 是默认的一种方式,因此这样的警告是没有必要的。
请记住,FindBugs 只是试图标记代码中潜在的可能问题,而不是所有可能的问题。您的第一个示例可能是潜在的维护问题,您需要检查它是否是真正的问题。您的第二个示例可能不是问题,或者它是一个实际问题,与它不是问题的用例太相似。
Its a form of aliasing, which may be counter-intuitive. Counter-intuitive code hampers ease of maintenance.
Logically, we expect instance methods to affect that instance's data. We expect static methods to affect static data.
Let's rename
doSomething
toinitialize
:The reader of this code may not immediately realize that the instances of
a
andb
are actually affecting the same data. This may be a bug since we're initializing the same memory twice, but its non-obvious since it seems reasonable that we may need to callinitialize
on each instance.However, the the code were:
In this case, its more intuitive that we're likely affecting the same static data and this is likely a bug.
This is similar to the common version of aliasing where two variables in the same scope point to the same instance.
For your last example,
an instance calls a static method
The fact that an instance method is calling a static method isn't expected to raise flags. The examples were this is useful far outweigh where its likely a problem.
a static method of one class affects another class' static data
In one sense, it should generate a different, but similar warning: that one class is messing with the data of another class. However, by making the static variable public is a way of tacitly approving of this, so such a warning isn't necessary.
Keep in mind that FindBugs is simply trying to flag potential likely problems, not every possible problem, in your code. Your first example is likely a potential maintenance issue that you need to examine whether its a real problem. Your second example is likely not a problem or it is a real problem that is too similar to use cases where it is not a problem.
关于为什么要更改静态字段的用例并不多。
请记住,如果将此字段设置为新值,则该类的所有实例的该值都会更改。
这可能会让您在多线程环境中陷入麻烦,因为在该环境中,多个线程正在调用
doSomething()
。需要适当的同步。在 99% 的情况下,您希望实例方法仅更改非静态字段,这就是 findbugs 向您发出警告的原因。
而且 findbugs 不够聪明,无法找出您的实例方法间接更改第二个示例中的字段:)
There aren't many use cases for why you would want to change a static field.
Remember that if you set this field to a new value that this value has changed for all instances of this class.
This might get you into trouble in a multi-threaded environment, where more than one thread is calling
doSomething()
. Proper synchronisation is required.In 99% of all cases, you want your instance methods to change the non-static fields only, which is why findbugs warns you.
And findbugs isn't clever enough to find out about your instance method indirectly changing the field in your second example :)
这是 FindBugs 对此的说法: http://findbugs.sourceforge.net/bugDescriptions.html #ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD
This is what FindBugs has to say about this: http://findbugs.sourceforge.net/bugDescriptions.html#ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD
这是我的看法,所以请持保留态度。您提到同步问题,这是此警告的主要原因,但更重要的是,这两种情况从根本上是在不同的数据概念“级别”上运行的。实例方法由对象“拥有”,并修改描述各个实例的数据。类方法是通用操作,虽然与类相关,但与单个对象无关。因此,从每个实例内部修改该状态可能(但不一定)是一个糟糕的设计决策。
This is my take, so take it with a grain of salt. You mentioned synchronization issues, which are a major reason for this warning, but more importantly, the two cases are fundamentally operating on different conceptual "levels" of data. Instance methods are "owned" by objects and modify data that describes individual instances. Class methods are generic operations and state that, while related to the class, are not related to individual objects. Thus, modifying that state from within each instance would probably (but not necessarily) be a poor design decision.
我认为同步(在几个答案中提到)对此没有任何影响。毕竟,静态方法可以像实例方法一样轻松地从多个线程调用。
我认为,警告的原因(FindBugs 文档没有很好地解释)是由几个答案暗示的:它是可疑的,并且可能是一个错误。正如 Jochen Bedersdorfer 所说,您希望从一个类中的实例方法分配给另一个类中的静态变量的用例并不多。就像这
在技术上不是一个错误(实际上如果 x 和 y 是布尔值,那么在 Java 中是合法的),它几乎总是一个错误。同样,FindBug 的作者对主题案例也有同样的感受。
I don't think synchronization (mentioned in several answers) has any bearing on this. After all, static methods can be called from multiple threads just as easily as can instance methods.
The reason for the warning (not very well explained by the FindBugs documentation) is, I think, hinted at by a couple of answers: it's suspicious and possibly a mistake. Like Jochen Bedersdorfer said, there aren't all that many use cases where you want to assign to a static variable in one class from an instance method in another. Just like
isn't technically an error (and actually legal Java if x and y are boolean), it's almost always a mistake. Similarly, the authors of FindBug felt the same about the subject case.
因为更改静态字段会更改所有实例的静态字段,如果未正确同步,则会导致无数问题。
如果您正在读取属性文件来设置共享字段,请在静态方法中执行此操作。或者,将字段重构为另一个类只能读取的单独的单例实例。如果您只想拥有一个实例,则使用单例模式并使字段成为非静态的。
静态方法应该只影响静态数据,实例方法应该只影响实例数据。
Because changing a static field changes it for all instances, causing untold problems if not properly synchronised.
If you're reading in a properties file to set shared fields, then do it in a static method. Alternatively, refactor the fields into a separate singleton instance that the other class can only read from. If you're only going to have one instance, then use a singleton pattern and make the fields non-static.
Static methods should only affect static data, and instance methods should only affect instance data.