使用使用 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
我搜索了 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