【问题标题】:Static Variables : Good or Bad? [duplicate]静态变量:好还是坏? [复制]
【发布时间】:2012-09-11 15:49:10
【问题描述】:

可能重复:
Why are static variables considered evil?

我有在所有程序中广泛使用静态变量的习惯,尤其是在我使用 Android 时。我倾向于使用它们,因为有时感觉通过 Intents 发送 10 个或更多值很麻烦。所以,我只是将它们声明为静态变量,并使用“点”运算符轻松地在其他类中访问它们。使用静态变量的另一个原因是当我制作一个 Utility 类 以在整个应用程序中使用时。就像我在下面给出的代码一样,可以帮助我在不同的活动中使用变量

Utility.java

public class Utility {
public static Facebook fb;
public static AsyncFacebookRunner fbAsyncRunner;
public static String[] fbPermissions = {"email", "read_stream", "user_birthday"};
public static final String PREF_UTILITY_FILE_NAME = "PrefUtilityFile";
public static SharedPreferences prefs;
public static Editor editor;
public static String access_token;
public static long expires;
}

我在网上搜索了类似的问题,遇到了thisthis,但他们似乎没有给出这个问题的最终答案。在大多数地方,我看到了相互矛盾的意见,因此完全感到困惑。

这是一个好的编程习惯还是坏的?我应该使用它还是不使用它?

【问题讨论】:

  • 就个人而言,我会说不好,因为您正在模拟全局变量。看看构建器模式。
  • 您使用它们的方式?不好。
  • 不是真的回答你的问题,所以我正在做评论。如果我遇到这样的代码,如果存储的东西相关,我会寻找什么。称为 Utility 的类在所有案例中的 90% 都像一个垃圾场。一系列不相关的东西。
  • 但他们没有最终答案并不意味着它不是重复的。存在相互矛盾的意见这一事实也不是开始第二个问题的理由,所以这就是我将其标记为重复的原因。

标签: java static


【解决方案1】:

如果你经常使用静态变量,我完全赞成静态变量,如果你把它们定为最终变量,它们的值永远不会改变。

为什么做事难?

这就是静态变量的全部用途。

他们所做的基本上是提供一个通用访问点,您可以从任何上下文(静态、程序流、外部)访问。

你基本上是在说前门在这里,它是黄色的。有人从外面偷看会看到黄色的门。在里面走的人会看到门,它是黄色的。 房间里的某个人可以看到走廊是黄色的。

如果你把它涂成红色,每个人都会清楚地看到它。

此外,在整个程序中总会有 1 个实例具有相同的值。节省内存。

举个例子

class test {
public int ten = 10;
   public test() {
   }
}

每次创建new test() 时,都会为十个变量分配一个整数内存空间。因此,如果您有 10 个测试实例,您将有 10 个单独的整数,它们都具有相同的值。

如果你有这个

class test {
public static int ten = 10;
   public test() {
   }
}

如果您有十个测试实例,那么您将只有 一个 整数实例十。这样可以节省内存分配和垃圾收集。虽然我只建议对于不会改变的持久列表/变量,并且您可以无条件地保留在内存中。不要对每个变量都这样做。对大型事物(例如您一遍又一遍地重复使用的图像)执行此操作。将同一张图片多次保存在内存中是没有用的。

当我最初写我的答案时,我不知道静态变量是如何工作的。我把static finalstatic 搞混了。在静态变量上,您可以分配新值。 static final 是不可变的。这些无法更改。

【讨论】:

  • 如果值发生变化怎么办?它们不是常量,可能会被意外修改。
  • 所以,这不是一个坏习惯,对吧? :D
  • @DarrenDavies :当您说“意外修改”时,您到底在说什么?
  • 如果我错了,请原谅我,但是只有当我声明为final时才会抛出异常?
  • @IgorGanapolsky 总结一下是的。
【解决方案2】:

您可以用“上下文”对象替换所有静态字段,您可以传递或制作单例。可以删除几乎所有的静态字段。这是否是一个好主意取决于您,但我不认为使用实例字段会变得更加困难。

顺便说一句:我建议

  • 将静态字段/常量放在使用它们的类或包中
  • 如果可能,将静态数组视为不可变数组,也将它们设为 final

您可以将非静态上下文与

一起使用
public class Context {
    public static final String PREF_UTILITY_FILE_NAME = "PrefUtilityFile";

    public Facebook fb;
    public AsyncFacebookRunner fbAsyncRunner;
    public String[] fbPermissions = {"email", "read_stream", "user_birthday"};
    public SharedPreferences prefs;
    public Editor editor;
    public String access_token;
    public long expires;
}

// pass to constructor as required
class UsesContext {
    final Context context;
    public UsesContext(Context context) {
        this.context = context;
    }

    public void method() {
        // can use context
    }
}

这允许您创建具有多个上下文的单元测试。

我唯一会保留静态的是常量。

【讨论】:

  • 感谢您的建议,但您能否详细解释一下如何使用上下文对象在不同的​​活动中使用我的变量?我已经使用上下文对象来制作 Toast 和其他东西,但是如何使用上下文访问变量?
  • 太棒了!我希望我能不止一次投票!非常感谢!
  • @PeterLawrey 我不会使用 'Context' 作为类的确切名称,因为它是 Android 框架中的现有类。
  • @PeterLawrey 为什么没有私有变量和公共 getter 和 setter ?基本上是封装。
  • @PunithRaj 封装可能是一种改进。尤其是如果这个类被你不能轻易改变的代码所使用。但是,如果您可以访问使用此类的所有代码,则添加 getter/setter 只会使代码复杂化。在可能的情况下将字段包设置为本地和final 也会有所帮助。
【解决方案3】:

这种编程实践在纯面向对象的语言(如 Java)中是不好的,因为它破坏了面向对象的编程范式。它们可以工作,但是一旦你意识到你确实需要它们的多个版本,你将需要大量的重构来实现这一点。

如果您认为通过方法调用处理太多参数很麻烦。只需创建一个包含所有这些对象的对象(请参阅 Peter Lawrey 的回答,“上下文”对象)并仅传递此对象。然后您可以再次在该对象上使用“简单点符号”。

下一点:测试。如果您需要用代理或其他测试内容替换一些静态字段以进行单元测试,那您基本上就完蛋了。使用上下文对象,您可以简单地将不同的上下文对象交给单元测试。

您提到的Utility 类基本上是此类上下文对象的良好候选者。只需将其所有字段设为非静态,并将该类的一个对象交给需要它的代码即可。

我可以告诉你一个我被静态方法搞砸的例子:我曾经写过一个编译器。而且由于我认为在编译运行期间,有许多上下文内容只需要一次(例如符号表),因此我将它们全部添加为静态变量。后来我决定允许多线程编译和“服务器”模式,其中编译器一直在空闲模式下运行,直到客户端发送编译请求(这节省了 Java 的长启动时间)。现在我被搞砸了。现在有不止一个并发上下文(并发编译器线程),但所有上下文都是通过静态变量共享的。我需要大约一周的时间将所有静态变量替换为上下文对象,并引入了许多错误。

【讨论】:

  • 您的经验是一个很好的例子,说明使用静态变量可能适得其反。感谢分享!
  • 这不是一个很好的例子,虽然也不错。如果您首先将应用程序设计为单线程,然后将其设计为多线程,那么许多其他事情也会随着静态而中断。即使是共享的正常状态变量、文件 i/o 和其他与状态相关的东西也会中断。那是因为你必须根据不同于你之前遵循的新范式来设计它。如果您想遵循相同的单线程设计但仍然有并行任务,您也可以通过分叉另一个进程来解决它。
  • @AbhinavGauniyal:但是编译器服务器是一个非常简单的无共享架构。两个编译请求几乎没有任何共同之处,因此使并发编译可用应该不是一项大任务。但是静态使它成为一项艰巨的任务。当然,我同意,将单线程程序转换为并发程序通常并不容易,但静态让它变得不必要地麻烦。
  • 这个答案的最后一部分,回答了我的问题,谢谢!。
【解决方案4】:

不好。见Cutting out Static

在我看来,静态变量包含一个或多个对象,但这些对象的格式不正确:没有按类组织(没有类型层次结构)、封装不好、仅限于单个实例(这可能会在将来、多个需要实例)。

【讨论】:

  • 感谢您的链接!真的很有帮助!
【解决方案5】:

声明为静态的变量会保留在内存中,直到程序执行,从而占用额外的空间。

如果您想长时间使用/保留一个值,使用静态可能会有所帮助,但是不建议将所有变量声明为静态,这不是一个好的做法。如果您养成将所有值声明为静态的习惯,您的程序将占用不必要的内存。

除此之外,静态变量不符合 OOPS 概念,其中范围、抽象和封装与冒泡对象一起定义。通过它可以随意调用和删除变量。

如果您在有限的内存空间(例如移动应用程序)中工作,则使用静态变量的最大缺点会出现,在这种情况下,如果变量过多且内存空间不足,您的应用程序将崩溃。

如果你想永久存储一个值,还有其他方法,比如数据库、文件等,可以让工作更轻松、更干净。 只是我的 2 美分。

【讨论】:

  • ~"声明为静态的变量会一直保留在内存中,直到程序执行,从而占用额外的空间。"公共静态变量和私有静态变量有很大区别。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-10-21
  • 2015-11-03
  • 2011-11-12
  • 2011-12-25
  • 2017-07-30
相关资源
最近更新 更多