【问题标题】:Difference Between Using Static Fields That Uses Getter And Setter And Static Fields That Are Declared Public使用使用 Getter 和 Setter 的静态字段与声明为 Public 的静态字段之间的区别
【发布时间】:2015-08-08 16:26:21
【问题描述】:

我搜索了保存/共享要在全球范围内使用的数据的最佳方法,正如预期的那样,我找到了很多答案。引起我注意的方法之一是使用静态字段。但是,那里的静态字段方式是这样的:

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 方法。而且我看不出两者有什么区别。那么为什么不推荐第二个呢?

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

【问题讨论】:

  • Static 方法很少用于这些尝试(getset)。
  • 您隐藏了实现细节(就像所有封装一样)。这使您可以在不破坏代码的情况下对其进行修改。如果您想将数据存储在Data 类型中,您可以更改字段变量,然后在setString 方法中将String 解析为Data(我建议更改名称),然后从@987654331 @ 到 StringgetString 方法中。
  • 您可能想阅读此链接,该链接主要讨论首先需要获取/设置方法! stackoverflow.com/questions/1568091/…
  • 如果这不是其他团队会使用的公共 API,请不要担心,裸字段没问题。以后可以随时重构。

标签: java memory-leaks shared-memory static-variables


【解决方案1】:

您关于内存泄漏的问题

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

想象它不是静态的:

public class DataHolder
{
   String dataString;
}

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

Getter 和 Setter 以及同步

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

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

话虽如此,您提供的代码 sn-p 在您的两个示例之间完全相同(为新函数生成新堆栈帧的差异很小),因为没有同步。你想这样做:

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' 不是静态上下文中的东西。

我做的另一件事是将同步放在方法中。我这样做有两个原因。首先是偏好;有些人更喜欢将同步保留在函数签名之外,这样它就不会被调用者混淆,所以他们不做假设,因为函数是同步的。那是偏好。我这样做的另一个原因是因为我想清楚地表明,当您在签名中同步一个函数时,它实际上是“幕后”的样子。如前所述,由于没有“this”,它实际上会在类本身上同步。

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

【讨论】:

    【解决方案2】:

    不要对内存泄漏有很多想法。

    但是:多个并行请求 - 多个线程,你肯定在这里遇到线程问题 - 这不是线程安全的,除非你照顾好(例如,使用 同步) .

    【讨论】:

      【解决方案3】:

      我更喜欢 getter/setter,而不是公共字段。

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

      如果您决定创建一个Data 类型,而不是将其存储为String,该怎么办? (为了提高类型安全性)。

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

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

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

      您应该将依赖项传递到需要它的地方,而不是全局访问某些东西。例如,使用全局变量的方法。通过参数将值传递给它。这称为依赖注入。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-08-28
        • 1970-01-01
        • 2016-08-31
        • 1970-01-01
        • 2019-05-29
        • 1970-01-01
        • 2014-07-16
        • 1970-01-01
        相关资源
        最近更新 更多