【问题标题】:Unable to declare static variable inside of static method无法在静态方法中声明静态变量
【发布时间】:2014-06-17 16:50:28
【问题描述】:
class Foo {
    public Foo() { }
}

class Bar {
    static Foo foo = new Foo(); // This is legal...

    public static void main(String[] args) { 
        static int a = 0; // ... But why this is not?
    }
}

为什么我们不能在静态函数中声明一个静态变量?

【问题讨论】:

  • 为什么这样做有意义?当谈论仅在方法体内部范围内的变量时,说它们是“类级别”是没有意义的。
  • @user3580294 我希望在静态循环中声明一个变量(这不是实际代码),这样它的值就不会随着下一次迭代而改变。
  • 所以你想要一个在方法调用中保持其值的变量?这不是 static 在 Java 中的含义。不过,我 99% 确定还有一个关于此的问题......
  • Java 的静态变量与 C 中的不同。该语言不是那样制作的。要想得到同样的效果,需要在静态方法之外做一个类变量。
  • 静态意味着内存中只存储了一个变量的副本。 final 表示变量永远不会改变。

标签: java


【解决方案1】:

您必须将final static 设为静态或删除static

在Java中,静态意味着它是一个类的变量/方法,它属于整个类,但不属于它的某个对象。这意味着静态关键字只能在“类范围”中使用。

通常,在 C 中,您可以静态分配局部范围的变量。不幸的是,Java 不直接支持这一点。但是你可以通过使用嵌套类来达到同样的效果。

例如,以下是允许的,但它是不好的工程,因为 x 的范围比它需要的大得多。两个成员(x 和 getNextValue)之间也存在不明显的依赖关系。

static int x = 42;
public static int getNextValue() {
    return ++x;
}

一个人真的很想这样做,但这是不合法的:

public static int getNextValue() {
    static int x = 42;             // not legal :-(
    return ++x;
}

但是你可以这样做,

public static class getNext {
    static int x = 42; 
    public static int value() {
        return ++x;
    }
}

以一些丑陋为代价的更好的工程。

【讨论】:

  • 仅仅因为 Java 不允许它并不意味着 static 不能“在方法内部有任何意义”。当然它可以,例如,static int getNextCounter() { static int x = 0; return x++; } 可以返回递增的值,并且您可以确信没有其他方法可以修改该x,因为它只具有该方法的范围。语言中没有包含某些内容并不意味着它没有任何意义。
  • 我们在public static class getNext 中不需要static,对吧?
  • “更好的工程,以牺牲一些丑陋为代价”似乎是 Java 中的一个共同主题,尽管“更好的工程”是有争议的。
  • “您必须使静态最终静态或删除静态”是什么意思?如果您的意思是字段foo,则可以将其定为final,但问题作者并没有问这个问题。如果您的意思是变量a,则不是这样——Java 变量可以是final,但不能是static final(或static)。
【解决方案2】:

其他人已经解释了如何在编码级别处理这个问题。请允许我解释为什么方法中的静态没有意义的逻辑和哲学原因。您必须提出“您希望变量持续多长时间?”的问题。

  • 普通成员变量的存在时间与它们所属的实例一样长;
  • 在方法中声明的变量持续到方法退出;
  • 静态类变量在类的生命周期内持续存在(即在大多数情况下永远存在)

那么,您希望您的“方法中的静态”变量持续多久?如果直到方法结束,那么您可以在没有静态的情况下使用它。如果是在类的生命周期内,那么您可以将其声明为静态成员变量。还有哪些其他选择?

C++ 允许在方法中使用静态变量,但它们最终的行为就像静态类变量一样,只是范围缩小了。即使在 C++ 中,它们也很少使用。它们最终也会像静态成员变量一样存储。这种模式被广泛认为是危险和令人困惑的,因为它意味着让一个方法“记住”从一个调用到另一个调用看起来像局部变量的值——如果其他一些代码选择这个值,这个值将会改变在两次调用之间执行方法。

Java 设计者认为少量的好处不值得增加语言的复杂性。

【讨论】:

  • "如果是在类的生命周期内,那么你可以将它声明为静态成员变量。还有哪些其他选项?"但是你在这里没有得到保证类中的一些其他方法不会修改它。这就是方法中的静态变量会给你的(正如你所指出的):有限的范围。有限的范围使得推理程序的行为变得更容易
  • 显然,方法内部的静态变量会遇到与类静态字段相同的并发问题。因此,即使是 C/C++ 用户也必须注意这一点。
【解决方案3】:

将变量声明为 final,而不是 static。

静态意味着每个类有一个,而不是每个类的实例一个。 final 表示创建后无法修改。 (尽管请注意,将引用设为 final 并不会使它引用的类不可变)。

换句话说,如果你有一个

final String[] array = new String[3];

您不能再更改该变量,例如,如果您想为它分配一个大小不同的新数组,而您无法更改。但是你可以修改数组的内容。

array[0] = "test";

因为这会修改内容,而不是数组本身。

同样的事情也适用于任何可变对象。

【讨论】:

  • 但是array[0]也是对字符串“test”的引用,尽管数组是最终的,但我们已经对其进行了重新编程,所以这就是你在()中提到这一行的原因。
  • @Bayant_singh final String[] array 表示 finalreference,而不是它指向的对象。
  • @Bayant_singh 我认为你是对的,但你的措辞有点含糊。把它想象成一个橱柜。通过使橱柜最终成为您将其构建到墙上的方法。你不能再移动橱柜,但你仍然可以把东西放进去拿东西。
【解决方案4】:

Java 不允许用户在本地创建静态变量,因为 java 静态变量的范围是全局的(即整个程序),因此没有必要在本地创建静态变量,因此为了避免歧义,java 不允许用户在本地创建静态变量。我们只能创建静态变量作为全局静态变量。

【讨论】:

    【解决方案5】:

    我想你的期望是像 static 局部变量在 C 函数中带有初始化器的行为,它只初始化一次,即在函数的第一次调用中,但在后续调用中没有。

    Java static 字段类似于 C static 局部变量,静态字段仅初始化一次,即在加载类时。

    关于提到它的其他答案,final 与此无关final 表示一个变量/字段的值在初始化后就不能再改变了。

    Java 中的惯用解决方案首先不使用 static 字段,但常量以及缓存和注册表之类的东西除外。

    通常,更好的解决方案是编写一个新类,而不是将您希望保留在“static”变量中的值作为常规(非静态)字段保存。您可以在字段声明或新类的构造函数中对其进行初始化,然后在(非静态)方法中执行您想要执行的计算。

    【讨论】:

      猜你喜欢
      • 2011-03-23
      • 1970-01-01
      • 2012-04-10
      • 2014-11-09
      • 1970-01-01
      • 1970-01-01
      • 2014-05-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多