修复此“从实例方法写入静态字段”findbugs 警告的最佳方法是啥?

Posted

技术标签:

【中文标题】修复此“从实例方法写入静态字段”findbugs 警告的最佳方法是啥?【英文标题】:What's the best way to fix this 'write to static field from instance method' findbugs warning?修复此“从实例方法写入静态字段”findbugs 警告的最佳方法是什么? 【发布时间】:2011-04-07 12:38:01 【问题描述】:

我有一个看起来与此类似的类,而 findbugz 抱怨“从实例方法写入静态字段”(initialize()killStaticfield())。我无法在 ctor 中设置静态字段。

解决此问题的最佳方法是什么?

将 staticField 放入 AtomicReference 就足够了吗?

 public class Something
 
  private static SomeClass staticField = null;
  private AnotherClass aClass;
  public Something()
  

  

  public void initialize()
  
    //must be ctor'd in initialize
    aClass = new AnotherClass();
    staticField = new SomeClass( aClass );
  

  public void killStaticField()
  
   staticField = null;
  

  public static void getStaticField()
  
    return staticField;
  

【问题讨论】:

为了回答您的问题,这个字段是静态的,因为 get 方法需要是静态的,这样其他对象才能访问 staticField 而无需引用 Something 对象。 基本上,我的问题是修复“从实例方法写入静态字段”findbugz 警告的最佳方法是什么;我只是编写了代码来表示警告。将静态对象包装在 AtomicReference 对象中更好还是同步更好? 【参考方案1】:

问题是你想用静态字段做什么。如果它针对您创建的每个类都发生了变化,那么让它完全静态可能不是一个好主意。如果它只被初始化一次,你应该懒惰地把它初始化为一个单例。

public class Something

    private static SomeClass staticField = null;

    public Something()
    

    

    public static SomeClass getStaticField()
    
        if(staticField == null)
            staticField = new SomeClass();;
        return staticField;
    

【讨论】:

别忘了让getStaticField方法synchronized 请注意,您不能只将 synchronized 放在静态方法定义上,因为静态方法使用 Something.class 进行同步! 我认为在讨论任何高级线程问题之前应该清楚静态变量的使用。抱歉,但您的问题听起来并不像您了解何时使用静态变量以及何时不使用。也许您可以再澄清一下您的问题。 @darrickc 在课堂上同步有什么问题?如果您的班级只是一个单身持有者(如您的示例),那么这是一个不错的同步解决方案。【参考方案2】:

如果 staticField 不应该是静态的,则从 staticField 中删除它。

将 kill 和 getStaticField 设为静态。而且您通常通过类名而不是(隐式) this 来引用静态,以非常清楚地表明它是静态的,并且可能会在其他线程中导致意想不到的后果。

如有疑问,请勿对非常量字段使用静态。

【讨论】:

您不需要“有疑问时”。【参考方案3】:

尽可能接近您的原始设计...

public class Something 
  private static volatile SomeClass staticField = null;

  public Something() 
  

  public static SomeClass getStaticField() 
    if(Something.staticField == null)
      Something.staticField = new SomeClass();;
    return Something.staticField;
  

通过类名引用您的静态变量,这将删除 findbugz 警告。 将您的静态变量标记为 volatile,这将使引用在多线程环境中更安全。

更好的是:

public class Something 
  private static final SomeClass staticField = new SomeClass();

  public Something() 
  

  public static SomeClass getStaticField() 
    return Something.staticField;
  

【讨论】:

但是没有同步的设计也意味着没有killStaticField。 你知道...看看第一个解决方案,它仍然不是线程安全的,即使变量是可变的。您必须在 if-null-then-new 部分周围放置一个 synchronized 块...我肯定更喜欢第二个选项。 我认为(不幸的是)第一个解决方案是我的正确答案。主要是因为我无法在顶部初始化 staticField,所以必须在调用 initialize() 后对其进行初始化(我将编辑问题以反映这一点)。 如果我们使用第一个代码块,我们必须使所有对 staticField 的访问在 SomeClass.class 周围同步。 我通过使用 ClassName.staticField 更改了它的引用,但是 findbugs 仍然抱怨同样的事情。【参考方案4】:

最好的办法是不做,尝试找到更好的设计模式。 如果真的有必要,这将起作用,并使 findbugs/spotbugs 不会抱怨。

public class Something

    private static SomeClass staticField = null;

    public Something()
    
    

    private void setStaticField(SomeClass value)
        staticField=value;
     

    public static SomeClass getStaticField()
    
        if(staticField == null)
            setStaticField(new SomeClass());
        return staticField;
    

【讨论】:

以上是关于修复此“从实例方法写入静态字段”findbugs 警告的最佳方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章

findbugs 可以检测未使用的公共方法吗

任何从没有站点:站点的 Maven 生成 Findbug HTML 报告的简单方法?

FindBugs IDEA - ClassNotFoundException com.google.wireless.android.sdk.stats.IntellijIndexingStats

FindBugs使用

Maven Findbugs 插件 - 如何在测试类上运行 findbug

idea2021安装及使用findBugs