使用使用 Getter 和 Setter 的静态字段与声明 Public 的静态字段之间的区别

Difference Between Using Static Fields That Uses Getter And Setter And Static Fields That Are Declared Public

我搜索了 hold/share 全球使用数据的最佳方法,正如预期的那样,我找到了很多答案。引起我注意的方法之一是使用静态字段。然而,那里的静态字段方式是这样的:

public class DataHolder
{
   private static String dataString;

   public static String getDataString
   {
      return dataString;
   }

   public static void setString(String dataString)
   {
      this.dataString = dataString;
   }
}

但我总是这样做:

public class DataHolder
{
   public static String dataString;
}

我只是想知道后者是不是比第一个容易得多?因为我不必设置任何 getter 和 setter 方法。而且我看不出两者有什么区别。那么为什么不推荐第二个呢?

我之前也被告知按照我的方式有时会导致内存泄漏问题。但是第一个解决方案不会导致内存泄漏问题吗?

不太了解内存泄漏。

但是:多个并行请求 - 多个线程,你这里肯定有线程问题 - 这不是线程安全的 除非你注意(例如使用 同步).

我更喜欢 getter/setters,而不是 public 字段。

这种封装允许您修改属性的类型而不破坏使用它的代码。

如果您决定创建 Data 类型而不是将其存储为 String 会怎样? (为了提高类型安全性)。

对于 public 字段,这是不可能的。但是使用 getter/setters,您可以执行允许此操作所需的解析:

class SomeClass {
    private static Data data;

    public static void setData(String data) {
        data = new Data(data);
    }

    public static String getData() {
        return data.toString();
    }
}

class Data {
    private String data;

    public Data(String data) {
        this.data = data;
    }

    public String toString() {
        return data;
    }
}

这不是内存泄漏问题,因为它与分配内存无关。使用该数据时线程之间可能存在一些不一致,因为它不是线程安全的,但任何泄漏都不会是使用静态的结果,而不是不正确的多线程。

与其全局访问某些内容,不如将依赖项传递到需要的地方。例如,使用全局变量的方法。通过参数将值传递给它。这称为依赖注入。

你关于内存泄漏的问题

首先我想说这里不会有内存泄漏问题。事实上,这两种情况都与内存泄漏完全相反(在这方面它们是相同的)。 DataHolder 只能有一个字符串实例 class(因为它是静态的,它不属于任何 DataHolder 实例)。

假设它不是静态的:

public class DataHolder
{
   String dataString;
}

这意味着每次执行 new DataHolder() 时,您都会有一个单独的字符串实例。使用静态数据字符串,将永远只有一个实例。

Getter 和 Setter 以及同步

正如 Piyush Mittal 指出的那样,您的实现之所以糟糕是因为它不是线程安全的。不过他没有透露任何细节,所以我想加上我的两分钱。

你不能因为你只希望它在单线程中使用就说它只会在单线程中使用。 Swing 线程就是一个很好的例子,其中只有一个线程处理 UI。在这种情况下,您会期望只存在一个线程,这样做是可以的。但是,任何后台工作都必须在 SwingWorker 线程中完成,因此在此处创建一个 SwingWorker 线程来执行此操作将提供数据竞争机会,因为现在有两个线程。出于这个原因,您应该始终为静态变量设置 getter 和 setter。

也就是说,您提供的代码片段在您的两个示例之间完全相同(为新函数生成新堆栈帧的细微差别),因为没有同步。你想这样做:

public class DataHolder{
  private static String dataString;
  public static String getDataString(){
    synchronized(DataHolder.class){
      return DataHolder.dataString;
    }
  }

  public static void setString(String dataString){
    synchronized(DataHolder.class){
      DataHolder.dataString = dataString;
    }
  }
}

我确实对您的代码进行了一些更改。第一个也是最明显的是没有用于静态变量的 this 关键字。正如我之前暗示的那样,因为它是静态的,所以它不属于任何实例。 'this' 不是静态上下文中的东西。

我做的另一件事是将 synchronized 放在方法中。我这样做有两个原因。首先是偏好;有些人更喜欢在函数签名之外保持同步,这样它就被调用者混淆了,所以他们不做假设,因为函数是同步的。那就是偏好。我这样做的另一个原因是因为我想让它很明显,当你在签名中同步一个函数时,这就是它实际看起来的样子 'under the hood'。如前所述,由于没有 'this',它实际上会在 class 本身上同步。

我认为您可能需要阅读一些有关 static 关键字的资料。我认为您的困惑来自您不理解它的事实,并且您试图在理解静态本身之前回答有关静态变量的 getter 和 setter 的问题。这是我通过快速 google 搜索找到的 link,可能会让您入门: http://www.javatpoint.com/static-keyword-in-java