关于java:静态变量:好还是坏?

Static Variables : Good or Bad?

本问题已经有最佳答案,请猛点这里访问。

Possible Duplicate:
Why are static variables considered evil?

我有在所有程序中广泛使用静态变量的习惯,尤其是在使用Android时。我倾向于使用它们,因为有时通过意图发送10个或更多的值会让人觉得很麻烦。所以,我只是将它们声明为静态变量,并使用"dot"操作符在其他类中轻松地访问它们。使用静态变量的另一个原因是,当我在整个应用程序中创建一个实用程序类时。像下面我给出的代码一样,可以帮助我在不同的活动中使用变量。

实用程序

1
2
3
4
5
6
7
8
9
10
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;
}

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

它是好的编程实践还是坏的?我是否应该使用它?


您可以用一个"context"对象替换所有静态字段,该对象可以传递或生成一个单例。几乎可以将所有静态字段都移除。这是否是一个好主意取决于您,但我不认为使用实例字段要困难得多。

顺便说一句:我建议

  • 将静态字段/常量与使用它们的类或包一起放置
  • 如果可能的话,将静态数组视为不可变数组,使它们也成为final

可以将非静态上下文用于

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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
    }
}

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

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


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

为什么事情总是那么困难?

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

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

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

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

此外,整个程序中始终有一个具有相同值的实例。这样可以节省内存。

举个例子

1
2
3
4
5
class test {
public int ten = 10;
   public test() {
   }
}

每次生成一个new test()时,都会为该10个变量分配一个整数内存空间。因此,如果您有10个测试实例,那么您将拥有10个单独的整数,所有这些整数都具有相同的值。

如果你有这个

1
2
3
4
5
class test {
public static int ten = 10;
   public test() {
   }
}

您有十个测试实例,您只有一个整数实例十。这样可以节省内存分配和垃圾收集。尽管我只建议持久的列表/变量不要改变,并且您可以独立地保存在内存中。不要对每个变量都这样做。对于像你一次又一次重复使用的图像这样的大型事物,可以这样做。在内存中多次保存同一图像是没有用的。

当我最初写我的答案时,我不知道静态变量是如何工作的。我把static finalstatic搞混了。在静态变量上,可以指定新值。静态final是不可变的。那些是不能改变的。


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

如果您认为通过方法调用处理太多参数是很麻烦的。只需创建一个包含所有对象的对象(参见彼得·劳里的回答,"上下文"对象)并只传递这个对象。然后你可以在那个对象上再次使用你的"简单点符号"。

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

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

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


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

如果您想长时间使用/保留一个值,那么使用static可能是有益的,但是不建议将所有变量声明为static,并且这不是一个好的实践。如果您习惯将所有值声明为静态值,那么您的程序将消耗不必要的内存。

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

如果您在有限的内存空间(如移动应用程序)中工作,那么使用静态变量的最大缺点将出现。在这种情况下,如果应用程序被变量过度占用而内存空间不足,那么它将崩溃。

如果您想永久地存储一个值,还有其他方法,比如数据库、文件等,可以使工作更简单、更干净。只有我的2美分。


坏的。请参见剪切静态。

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