Java中的全局变量

270

在Java中如何定义全局变量?


23
你能告诉我们在Java中为什么要定义全局变量吗? - Adam Paynter
53
从类外部访问变量。 - aTJ
7
也许你应该编辑你的问题,加入一些示例代码来准确说明你想要什么。这将有助于我们推荐最佳解决方案。 - Adam Paynter
8
我可以把一个类中的变量值从另一个类改变。 - aTJ
4
不需要。Java 中没有全局变量。 - user207421
@aTJ 我认为全局变量应该可以被同一类中的所有私有(或更轻松限制的)方法访问,即Java中的成员变量。 - HellishHeat
25个回答

316

为定义全局变量,你可以使用 static 关键字。

public class Example {
    public static int a;
    public static int b;
}

现在你可以通过调用 a 和 b 来从任何地方访问它们。

Example.a;

Example.b;

18
在进行此操作时需要小心 - 当全局类被卸载时,变量将变为未定义的空值。如果你出售你的应用程序,这迟早会发生,并且你会到处寻找错误,但实际上错误就在那里... - user387184
11
static 关键字使变量在类加载时全局可访问。 - sjas
27
关于类卸载:如果存在任何强引用链,从任何GC Root到Global或其子类的实例,或者从已加载但无法卸载的类到Global的编译时引用,则与Global相关的Class对象是强可达的,因此加载Global的ClassLoader也是强可达的。这使得卸载Global变得不可能(因为类卸载只能在GC完全删除加载给定类的ClassLoader的任何强引用后发生)。如果您完全没有引用,那么卸载将不会成为问题吗? - Bruno Reis
7
我建议你将类名从 Global 改为其他名称(比如 TestClass),以免让人们误认为这是 Java 的关键字。谨慎总比后悔好 :) - Nicolas Rinaudo
@user387184 总之,只要有对那个“全局”类的引用,值就不会突然变为null,对吧? - amey91
1
当多个线程修改和读取这些变量时,它们将如何工作,为什么不使用public static volatile int a;? - Sergey Shcherbakov

59

不需要这样做,这是有意设计的。即使你可以这样做,你也不应该这样做。

话虽如此,你可以在一个名为Globals的类中创建一组公共静态成员。

public class Globals {
   public static int globalInt = 0;
   ///
}

但你真的不应该这样做:)。说真的...不要这么做。


1
正如我之前所写的那样 - 当类被卸载时,变量将失去其值并且您的应用程序将崩溃。 - user387184
8
那么,我应该采用什么更好的方法来声明常量,以便所有类方法都可以访问它们? - Alston
10
这类帖子是新手产生全局变量恐惧症的原因,接着我们看到各种极端技巧被想出来规避全局变量禁忌,以达到相同的效果。 - Evgeni Sergeev
60
不解释或参考原因地说“别这样做”而遭到负评。 - Jeff McCune
17
我会做这件事。 - Floating Sunfish
当一个变量被多个线程修改和读取时,它将如何工作,为什么不使用... public static volatile int globalInt; - Sergey Shcherbakov

50

另外一种方法是创建一个像这样的接口:

public interface GlobalConstants
{
  String name = "Chilly Billy";
  String address = "10 Chicken head Lane";
}

任何需要使用它们的类只需实现该接口:

public class GlobalImpl implements GlobalConstants
{
  public GlobalImpl()
  {
     System.out.println(name);
  }
}

22
“常量接口模式是接口的滥用。”这本书值得一读! :) - MariuszS
这本书中的另一个评论是:“常量接口反模式 - 不要使用!” - MariuszS
1
另外,从JDK 1.5+开始,您可以使用静态导入来处理全局变量,无需实现。 - MariuszS
12
好的,那并没有解释任何事情,只是说有些书说它不好。 - linkhyrule5
18
这里有一句话给你。Oracle说:“为了避免这种情况,人们有时会将静态成员放入接口中并从该接口继承。这是一个坏主意。事实上,它是如此糟糕,以至于有一个名字:常量接口反模式(请参见Effective Java Item 17)。问题在于,类对另一个类的静态成员的使用仅是实现细节。当一个类实现一个接口时,它成为类的公共API的一部分。实现细节不应泄漏到公共API中。” - Jolta
显示剩余5条评论

25

你最好使用依赖注入:

public class Globals {
    public int a;
    public int b;
}

public class UsesGlobals {
    private final Globals globals;
    public UsesGlobals(Globals globals) {
        this.globals = globals;
    }
}

5
没错,虽然我认为你使用“Globals”这个词有点让人困惑 :-). “Parameters”这样的词更合适,因为它不一定是全局的。 - Mark Peters

14

有很多好的答案,但我想给出这个例子,因为它被认为是通过另一个类访问类变量的更合适的方法:使用getter和setter。

为什么要以这种方式使用getter和setter而不是只将变量公开呢?原因是这样,假设你的变量将成为一个全局参数,在程序执行期间永远不会被更改(在与团队一起开发代码的情况下),比如可能是网站的URL。理论上,这可能会多次更改并在程序中使用,所以您希望使用全局变量以便能够一次性更新它。但是,您不希望其他人去更改此变量(可能没有意识到它的重要性)。在这种情况下,您只需不包括setter方法,仅包括getter方法即可。

public class Global{
    private static int var = 5;

    public static int getVar(){
        return Global.var;
    }

    //If you do not want to change the var ever then do not include this
    public static void setVar(int var){
        Global.var = var;
    }
}

应该是 public static class 吗? - Cloud Cho
1
这不是一个有效的Java命令。我认为它甚至不能编译。 - Dan Ciborowski - MSFT
你的意思是说,如果我们创建一个名为Global.java的文件,那么这个类声明就无效了吗?实际上我把你的“Global”类做成了一个子类。 - Cloud Cho

13

实际上,在Java面向对象程序中没有“全局”概念。

然而,你的问题背后确实有一些真相,因为会有一些情况需要在程序的任何部分运行方法。例如,在Phrase-O-Matic应用程序中,random()方法应该可以从程序的任何地方调用。

因此,为了满足类似于上述的需求,“我们需要像全局变量和方法这样的东西”。

要声明一个变量为全局变量:

 1.Mark the variable as public static final While declaring.

声明方法为全局方法.

 1. Mark the method as public static While declaring.
因为我将全局变量和方法声明为静态的,所以你可以通过以下代码在任何地方调用它们:
ClassName.X
注意:X可以是所需的方法名或变量名,而ClassName是你声明它们的类的名称。

12

Java 中没有全局变量。

然而,我们有一个 static 关键字, 这已经足够。在 Java 中,没有类外的东西存在。 static 关键字表示一个类变量,与实例变量相反,它只有一个副本并且跨越创建的该类的所有实例,这意味着它的值可以在任何实例中被更改和访问。

如果您需要一个可以超越作用域访问的全局变量,则需要使用此变量,但其范围仅限于类所在的范围。


11

除了常量,没有什么应该是全局的。

public class MyMainClass {
    public final static boolean DEBUGMODE=true;
}

将此代码放入您的主类中。在其他 .java 文件中,通过以下方式使用:

if(MyMainClass.DEBUGMODE) System.out.println("Some debugging info");

确保在将您的代码从剪切室移出并发布时,删除或注释掉此功能。

如果您有一个像随机器这样的工作方法,我建议创建一个“工具箱”包!所有编程人员都应该有一个,然后每当您想在.java文件中使用它时,只需导入即可!


6

在Java中,不存在真正的全局变量。每个静态变量都必须属于某个类(比如System.out),但是当你决定将它放在哪个类中时,你可以在同一个类加载器加载的所有地方引用它。

请注意,在更新静态变量时,应始终进行保护以避免竞态条件。


1
Java不提供全局变量功能,但如果您想要全局变量的概念,我们可以利用static关键字。 - Abi

4

理解问题

我认为“全局变量”的资格是指在代码中任何地方都可以访问和更改,而不需要关心静态/实例调用或传递任何来自一个类到另一个类的引用。

通常如果你有A类:

public class A {
    private int myVar;

    public A(int myVar) {
        this.myVar = myVar;
    }

    public int getMyVar() {
        return myVar;
    }

    public void setMyVar(int mewVar) {
        this.myVar = newVar;
    }
}

我想要在B类中访问和更新myvar

public class B{

    private A a;

    public void passA(A a){
        this.a = a;
    }

    public void changeMyVar(int newVar){
        a.setMyvar(newVar);
    }
}

你需要拥有类A的一个实例引用,并且按照下面的方式更新类B中的值:
int initialValue = 2;
int newValue = 3;
A a = new A(initialValue);
B b = new B();
b.passA(a);
b.changeMyVar(newValue);
assertEquals(a.getMyVar(),newValue); // true

解决方案

那么,我的解决方案是使用单例模式(虽然我不确定这是否是一个好的做法):


public class Globals {
    private static Globals globalsInstance = new Globals();

    public static Globals getInstance() {
        return globalsInstance;
    }

    private int myVar = 2;

    private Globals() {
    }

    public int getMyVar() {
        return myVar;
    }

    public void setMyVar(int myVar) {
        this.myVar = myVar;
    }
}

现在,您可以通过以下方式在任何地方获得全局唯一实例:

Globals globals = Globals.getInstance();
// and read and write to myVar with the getter and setter like 
int myVar = globals.getMyVar();
global.setMyVar(3);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接