Biến toàn cục trong Java


217

Làm thế nào để bạn xác định các biến toàn cầu trong Java?


20
Bạn có thể cho chúng tôi biết lý do tại sao bạn muốn xác định các biến toàn cục trong Java không?
Adam Paynter

44
Để truy cập biến từ bên ngoài lớp
aTJ

5
Có lẽ bạn nên chỉnh sửa câu hỏi của mình để bao gồm một số mã mẫu minh họa chính xác những gì bạn muốn. Nó sẽ giúp chúng tôi đề xuất giải pháp tốt nhất.
Adam Paynter

7
@Adam: Tôi sẽ có thể thay đổi giá trị của một biến trong một lớp từ một lớp khác.
aTJ

2
Bạn không. Không có biến toàn cục trong Java.
Hầu tước Lorne

Câu trả lời:


261

Để xác định Biến toàn cầu, bạn có thể sử dụng Từ khóa tĩnh

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

bây giờ bạn có thể truy cập a và b từ bất cứ đâu bằng cách gọi

Example.a;

Example.b;

6
"Toàn cầu" là tên của lớp.
Jerome

12
Hãy cẩn thận khi làm điều này - khi lớp Toàn cầu được tải, các biến sẽ không được xác định là null. Nếu bạn bán ứng dụng của mình, điều này sẽ xảy ra sớm hay muộn và bạn cứ tìm lỗi ở mọi nơi nhưng không có ở đó ....
user387184

10
Các statictừ khóa làm biến truy cập trên toàn cầu, trong khi lớp học của họ được tải.
sjas

22
Về việc dỡ lớp: nếu có bất kỳ chuỗi tham chiếu mạnh nào từ bất kỳ Root gốc nào đến một thể hiện của Toàn cầu hoặc các phần tử con của nó hoặc bất kỳ tham chiếu thời gian biên dịch nào từ một lớp được tải và không thể tải lên Toàn cầu, thì đối tượng Lớp liên quan đến Toàn cầu rất mạnh có thể truy cập và do đó, ClassLoader cũng đã tải Toàn cầu; điều này làm cho không thể tải Toàn cầu (vì việc dỡ lớp chỉ có thể xảy ra sau khi GC loại bỏ hoàn toàn mọi tham chiếu mạnh đến Trình tải lớp đã tải một lớp đã cho). Nếu bạn không có tài liệu tham khảo nào cả, làm thế nào việc dỡ tải có thể là một vấn đề ???
Bruno Reis

4
@Abi Tôi đề nghị đổi tên lớp của bạn từ Globalmột thứ khác ( TestClass?) Để không tạo cho mọi người ấn tượng rằng có một thứ như Globaltừ khóa Java. An toàn tốt hơn xin lỗi :)
Nicolas Rinaudo

53

Bạn không. Đó là do thiết kế. Bạn không nên làm điều đó ngay cả khi bạn có thể.

Điều đó đang được nói rằng bạn có thể tạo một tập hợp các thành viên tĩnh công khai trong một lớp có tên là Globals.

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

nhưng bạn thực sự không nên :). Nghiêm túc .. đừng làm điều đó.


6
Vậy thì cách tiếp cận tốt hơn mà tôi có thể khai báo các hằng số để tất cả các phương thức lớp có thể truy cập chúng là gì?
Alston

6
Bài viết có tính chất này là lý do người mới phát triển nỗi ám ảnh biến toàn cầu, và sau đó chúng ta thấy tất cả các loại kỹ thuật tầm thường đang được nghĩ ra để phá vỡ điều cấm kỵ biến toàn cầu, nhưng đạt được hiệu quả tương tự.
Evgeni Sergeev

38
Bỏ phiếu để nói, "đừng làm điều đó." mà không giải thích hoặc đề cập đến một lời giải thích tại sao.
Jeff McCune

4
@JeffMcCune: để làm cho tuyên bố của bạn rõ ràng hơn, "đừng làm điều đó" thực sự là nhảm nhí. Làm điều đó khi nó hữu ích. Ví dụ: tôi phải gỡ lỗi mã của mình bằng cách sử dụng một số IAbTHERLoggerBullshit và tất nhiên System.err không hoạt động trong môi trường quá đông này. Tôi không thể xả mã của mình đi xung quanh crap logger giữa hàng trăm lớp bộ điều hợp vô dụng.
Jo So

6
Tôi sẽ làm điều đó.
Cá mặt trời nổi 23/11/18

40

Một cách khác là tạo một giao diện như thế này:

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

Bất kỳ lớp nào cần sử dụng chúng chỉ phải thực hiện giao diện:

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

Tôi tự hỏi tại sao câu trả lời này (trước tôi) không có phiếu bầu. Nó không cung cấp một câu trả lời thay thế hợp lý cho câu trả lời được cung cấp bởi tất cả các câu trả lời khác?
M_M

12
Java hiệu quả của Joshua Bloch, Chương 4: Các lớp và giao diện, Mục 19: Chỉ sử dụng các giao diện để xác định các loại "Mẫu giao diện không đổi là việc sử dụng giao diện kém." Cuốn sách này đáng đọc! :)
MariuszS

1
Ngoài ra, từ JDK 1.5+, bạn có thể sử dụng nhập tĩnh cho các biến toàn cục của mình, không cần thực hiện.
MariuszS

9
.... Phải, điều đó không thực sự giải thích bất cứ điều gì, điều đó chỉ nói rằng một số cuốn sách nói rằng nó là xấu.
linkhyrule5

14
Đây là một trích dẫn cho bạn. Oracle nói: "Để giải quyết vấn đề này, đôi khi người ta đặt các thành viên tĩnh vào một giao diện và kế thừa từ giao diện đó. Đây là một ý tưởng tồi. Trên thực tế, đó là một ý tưởng tồi tệ đến nỗi có một cái tên cho nó: Constant Interface Antipotype (xem Mục Java hiệu quả 17). Vấn đề là việc sử dụng các thành viên tĩnh của một lớp khác là một chi tiết triển khai đơn thuần. Khi một lớp thực hiện một giao diện, nó trở thành một phần của API công khai của lớp. API công khai. "
Jolta

23

Bạn nên sử dụng tiêm phụ thuộc:

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

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

5
Đúng, mặc dù tôi nghĩ rằng việc bạn sử dụng "Globals" gây nhầm lẫn một chút :-). Một cái gì đó như "Thông số" sẽ phù hợp hơn vì nó không nhất thiết phải là Toàn cầu.
Mark Peters

11

Rất nhiều câu trả lời hay, nhưng tôi muốn đưa ra ví dụ này vì nó được coi là cách thích hợp hơn để truy cập các biến của một lớp bởi một lớp khác: sử dụng getters và setters.

Lý do tại sao bạn sử dụng getters và setters theo cách này thay vì chỉ công khai biến là như sau. Hãy nói rằng var của bạn sẽ là một tham số toàn cầu mà bạn KHÔNG BAO GIỜ muốn ai đó thay đổi trong quá trình thực thi chương trình của bạn (trong trường hợp khi bạn đang phát triển mã với một nhóm), giống như có thể là URL cho một trang web. Về lý thuyết, điều này có thể thay đổi và có thể được sử dụng nhiều lần trong chương trình của bạn, vì vậy bạn muốn sử dụng var toàn cầu để có thể cập nhật tất cả cùng một lúc. Nhưng bạn không muốn người khác đi vào và thay đổi var này (có thể mà không nhận ra tầm quan trọng của nó). Trong trường hợp đó, bạn chỉ đơn giản là không bao gồm một phương thức setter và chỉ bao gồm phương thức 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;
    }
}

10

Không có biến toàn cục trong Java

Tuy nhiên, những gì chúng ta có là một statictừ khóa và đó là tất cả những gì chúng ta cần. Không có gì tồn tại bên ngoài lớp trong Java. Cácstatic từ khóa đại diện cho một biến lớp đó, trái với biến Ví dụ, chỉ có một bản sao và vượt trên tất cả các trường hợp của lớp đó được tạo ra, có nghĩa là giá trị của nó có thể được thay đổi và truy cập trên tất cả các trường hợp bất cứ lúc nào.

Nếu bạn cần một biến toàn cục có thể được truy cập ngoài phạm vi, thì đây là biến mà bạn cần, nhưng phạm vi của nó chỉ tồn tại ở nơi có lớp và đó sẽ là tất cả.


9

Thực sự mà nói không có khái niệm "TOÀN CẦU" trong chương trình java OO

Tuy nhiên, có một số sự thật đằng sau câu hỏi của bạn bởi vì sẽ có một số trường hợp bạn muốn chạy một phương thức tại bất kỳ phần nào của chương trình. Ví dụ: phương thức Random () trong ứng dụng Phrase-O-Matic, đây là một phương thức có thể gọi được từ bất kỳ đâu trong chương trình.

Vì vậy, để đáp ứng những điều như trên "Chúng ta cần phải có các biến và phương thức giống như Toàn cầu"

ĐỂ KHAI THÁC MỘT BIẾN ĐỔI NHƯ TOÀN CẦU.

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

ĐỂ KHAI THÁC MỘT PHƯƠNG PHÁP NHƯ TOÀN CẦU .

 1. Mark the method as public static While declaring.

Bởi vì tôi đã khai báo các biến và phương thức toàn cục là tĩnh, bạn có thể gọi chúng ở bất cứ đâu bạn muốn chỉ bằng sự trợ giúp của mã sau

Tên lớp.X

LƯU Ý : X có thể là tên phương thức hoặc tên biến theo yêu cầu và ClassName là tên của lớp mà bạn đã khai báo chúng.


9

Không có gì nên là toàn cầu, ngoại trừ hằng số.

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

Đặt cái này trong lớp học chính của bạn. Trong các tệp .java khác, sử dụng thông qua:

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

Hãy chắc chắn rằng khi bạn di chuyển mã của mình ra khỏi sàn phòng cắt và phát hành, bạn loại bỏ hoặc nhận xét chức năng này.

Nếu bạn có một phương pháp phù hợp, như ngẫu nhiên, tôi khuyên bạn nên tạo gói "Hộp công cụ"! Tất cả các lập trình viên nên có một, sau đó bất cứ khi nào bạn muốn sử dụng nó trong .java, chỉ cần nhập nó!


5

Không có thứ gọi là biến toàn cầu thực sự trong Java. Mỗi biến tĩnh phải thuộc về một số lớp (như System.out), nhưng khi bạn đã quyết định nó sẽ đi vào lớp nào, bạn có thể tham chiếu đến nó từ mọi nơi được tải bởi cùng một trình nạp lớp.

Lưu ý rằng các biến tĩnh phải luôn được bảo vệ khi cập nhật để tránh điều kiện cuộc đua.


1
java không cung cấp biến toàn cục theo chức năng nhưng nếu bạn muốn có một khái niệm biến toàn cục, chúng ta có thể sử dụng từ khóa tĩnh
Abi

3
public class GlobalClass {
     public static int x = 37;
     public static String s = "aaa";
}

Bằng cách này bạn có thể truy cập chúng với GlobalClass.xGlobalClass.s


2
public class GlobalImpl {   

 public static int global = 5;

}

bạn có thể gọi bất cứ nơi nào bạn muốn:

GlobalImpl.global // 5

1

Như bạn có thể đoán từ câu trả lời, không có biến toàn cục trong Java và điều duy nhất bạn có thể làm là tạo một lớp với các thành viên tĩnh:

public class Global {
    public static int a;
}

Bạn có thể sử dụng nó với Global.anơi khác. Tuy nhiên, nếu bạn sử dụng Java 1.5 hoặc tốt hơn, bạn có thể sử dụng import staticphép thuật để làm cho nó trông giống như một biến toàn cục thực sự:

import static test.Global.*;

public class UseGlobal {
    public void foo() {
        int i = a;
    }
}

voilà !

Bây giờ đây là một cách thực hành tốt nhất để bạn có thể thấy trong quảng cáo: đừng làm điều này ở nhà


1

Không có biến toàn cục trong Java, nhưng có các lớp toàn cầu với các trường công khai. Bạn có thể sử dụng tính năng nhập tĩnh của java 5 để làm cho nó trông gần giống như các biến toàn cục.


1

Nói chung biến toàn cầu (tôi giả sử bạn đang so sánh nó với C, Cpp) xác định là public static final

giống

class GlobalConstant{
    public static final String CODE  = "cd";
}

ENUM cũng hữu ích trong trường hợp như vậy:

Ví dụ Calendar.JANUARY)


Liệu một biến toàn cầu cần phải là cuối cùng? Tại sao?
Konerak

1
"Final" có nghĩa là "hằng số", vì vậy đây là hằng số toàn cầu.
duffymo

1
không, đó là biến toàn cầu có nghĩa là gì nếu bạn muốn chia sẻ biến đó và thay đổi dữ liệu sau đó chỉ cần xóa finalnhưng nó chắc chắn phụ thuộc vào cách bạn muốn chia sẻ, nơi bạn đang sử dụng và tất cả,
Jigar Joshi

Loại CODEtrong ví dụ này là gì? Nó được định nghĩa ở đâu?
M_M

Cũng lưu ý: CODE có trong tất cả các giới hạn, vì ký hiệu java phổ biến của nó để sử dụng tất cả các giới hạn cho các biến mà bạn khai báo là cuối cùng và không có ý định thay đổi trong quá trình của chương trình.
Dan Ciborowski - MSFT

1

Tạo một tệp độc lập, ví dụ. Example.java để sử dụng giải pháp thứ 1, thật tốt. Bạn cũng có thể làm điều đó trong ứng dụng, ví dụ: các biến toàn cục là đặc biệt đối với ứng dụng hiện tại của bạn, v.v.:

Tạo một lớp ở đầu và khai báo các biến của bạn trong đó:

class Globals {
  static int month_number;
  static String month_name;
}

Sau đó, bạn có thể truy cập các biến này - sử dụng chúng dưới dạng 'Globals.month_number', v.v. - từ mọi nơi trong ứng dụng của bạn.


Thay vì downvote, bạn có thể vui lòng cho tôi biết có gì sai với giải pháp này? Tôi đang sử dụng nó một cách thường xuyên và nó là một trong những thuận tiện nhất. Vì vậy, tôi không thể làm khác đi việc coi downvote này là một việc cá nhân hoặc chỉ được thực hiện bởi một người ngu ngốc.
Tông đồ

1

Nếu bạn cần cập nhật thuộc tính toàn cục, một lớp bao bọc getter / setter đơn giản có thể được sử dụng làm biến toàn cục. Một ví dụ điển hình được hiển thị dưới đây.

public class GlobalHolder {

    private static final GlobalHolder INSTANCE = new GlobalHolder();

    private volatile int globalProperty;

    public static GlobalHolder getInstance() {
        return INSTANCE;
    }

    public int getGlobalProperty() {
        return globalProperty;
    }

    public void setGlobalProperty(int globalProperty) {
        this.globalProperty = globalProperty;
    }

    public static void main(String[] args) {
        GlobalHolder.getInstance().setGlobalProperty(10);
        System.out.println(GlobalHolder.getInstance().getGlobalProperty());
    }
}

0

Theo khái niệm, các biến toàn cục, còn được gọi là biến thể hiện là các biến cấp độ lớp, nghĩa là chúng được định nghĩa bên trong một lớp nhưng các phương thức bên ngoài. Để làm cho chúng có sẵn hoàn toàn và sử dụng chúng trực tiếp cung cấp từ khóa tĩnh. Vì vậy, nếu tôi đang viết một chương trình cho hoạt động số học đơn giản và nó yêu cầu một cặp số thì hai biến đối tượng được định nghĩa như sau:

public class Add {
    static int a;
    static int b; 
    static int c;

    public static void main(String arg[]) {
        c=sum();
        System.out.println("Sum is: "+c); 
    }

    static int sum() {
       a=20;
       b=30;
       return a+b;   
    }
}

Output: Sum is: 50

Ngoài ra, sử dụng từ khóa tĩnh trước các biến đối tượng cho phép chúng tôi không chỉ định kiểu dữ liệu cho cùng một biến lặp đi lặp lại. Chỉ cần viết biến trực tiếp.


1
Không có biến toàn cục trong Java; chúng không được gọi là các biến thể hiện; định nghĩa chúng là statickhông "làm cho chúng có sẵn hoàn toàn". Đoạn đầu là vô nghĩa. Ví dụ là thực hành kém.
Hầu tước Lorne

0

Nói chung, Java không có bất kỳ biến toàn cục nào. Khác với các biến cục bộ, tất cả các biến đều thuộc phạm vi của bất kỳ lớp nào được định nghĩa trong chương trình. Chúng ta có thể có các biến tĩnh để có phạm vi của các biến toàn cục.


0

không có staticđiều này là có thể quá:

class Main {
  String globalVar = "Global Value";

  class Class1 {
    Class1() {
      System.out.println("Class1: "+globalVar);
      globalVar += " - changed";
  } }
  class Class2 {
    Class2() {
      System.out.println("Class2: "+globalVar);
  } }

  public static void main(String[] args) {  
    Main m = new Main();
    m.mainCode();
  }
  void mainCode() {
    Class1 o1 = new Class1();
    Class2 o2 = new Class2();
  }
}

/*
Output:
Class1: Global Value
Class2: Global Value - changed
*/

0

Lập trình hướng đối tượng được xây dựng với sự hiểu rằng phạm vi của các biến là độc quyền chặt chẽ với đối tượng lớp đóng gói các biến đó.

Vấn đề với việc tạo ra "các biến toàn cục" là nó không phải là tiêu chuẩn công nghiệp cho Java. Đây không phải là tiêu chuẩn công nghiệp vì nó cho phép nhiều lớp thao tác dữ liệu không đồng bộ hóa, nếu bạn đang chạy một ứng dụng đa luồng, điều này sẽ phức tạp và nguy hiểm hơn một chút về mặt an toàn của luồng. Có nhiều lý do khác khiến việc sử dụng các biến toàn cục là không hiệu quả, nhưng nếu bạn muốn tránh điều đó, tôi khuyên bạn nên dùng đến Lập trình hướng theo khía cạnh .

Lập trình hướng theo khía cạnh phủ nhận vấn đề này bằng cách đặt lớp cha phụ trách phạm vi thông qua một cái gì đó gọi là "lời khuyên", bổ sung thêm hành vi cho mã mà không thực sự sửa đổi nó. Nó cung cấp các giải pháp cho mối quan tâm xuyên suốt, hoặc sử dụng biến toàn cầu.

Spring là một khung công tác Java sử dụng AOP và mặc dù nó được sử dụng theo cách truyền thống cho các ứng dụng web, ứng dụng cốt lõi có thể được sử dụng phổ biến trong toàn bộ khung Java (bao gồm 8.0). Đây có thể là một hướng bạn muốn khám phá thêm.


0

Hiểu vấn đề

Tôi coi chất lượng của biến toàn cục là một biến có thể được truy cập và thay đổi ở bất kỳ đâu trong mã mà không quan tâm đến lệnh gọi tĩnh / thể hiện hoặc chuyển bất kỳ tham chiếu nào từ lớp này sang lớp khác.

Thông thường nếu bạn có lớp 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;
    }
}

và muốn truy cập và cập nhật myvartrong lớp B,

public class B{

    private A a;

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

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

bạn sẽ cần phải có một tham chiếu của một thể hiện của lớp A và cập nhật giá trị trong lớp B như thế này:

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

Giải pháp

Vì vậy, giải pháp của tôi cho vấn đề này, (ngay cả khi tôi không chắc liệu đó có phải là một cách thực hành tốt hay không), là sử dụng một singleton:


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;
    }
}

Bây giờ bạn có thể lấy phiên bản duy nhất toàn cầu ở bất cứ đâu với:

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

-1
// Get the access of global while retaining priveleges.
// You can access variables in one class from another, with provisions.
// The primitive must be protected or no modifier (seen in example).

// the first class
public class farm{

  int eggs; // an integer to be set by constructor
  fox afox; // declaration of a fox object

  // the constructor inits
  farm(){
    eggs = 4;
    afox = new fox(); // an instance of a fox object

    // show count of eggs before the fox arrives
    System.out.println("Count of eggs before: " + eggs);

    // call class fox, afox method, pass myFarm as a reference
    afox.stealEgg(this);

    // show the farm class, myFarm, primitive value
    System.out.println("Count of eggs after : " + eggs);

  } // end constructor

  public static void main(String[] args){

    // instance of a farm class object
    farm myFarm = new farm();

  }; // end main

} // end class

// the second class
public class fox{

  // theFarm is the myFarm object instance
  // any public, protected, or "no modifier" variable is accessible
  void stealEgg(farm theFarm){ --theFarm.eggs; }

} // end class

2
Câu trả lời này thêm gì mà các câu trả lời khác không có? Tôi không thể thấy bất kỳ giá trị "mới" nào trong câu trả lời này.
EWit

-2

Để xác định Biến toàn cầu, bạn có thể sử dụng Từ khóa tĩnh

public final class Tools {
  public static int a;
  public static int b;
}

bây giờ bạn có thể truy cập a và b từ bất cứ đâu bằng cách gọi

Tools.a;
Tools.b;

Yoy đúng ... đặc biệt trong J2ME ... Bạn có thể tránh NullPulumException bằng cách đặt bên trong hàm tạo MidLet của bạn (khởi tạo proggy) dòng mã này:

new Tools();

Điều này đảm bảo rằng Công cụ sẽ được phân bổ trước bất kỳ hướng dẫn nào sử dụng nó.

Đó là nó!


3
Ừm ... Xin lỗi, nhưng phần bổ sung này chưa được bao phủ bởi các câu trả lời hiện có?
Bí ẩn

Có lẽ bạn đúng..nhưng câu trả lời này giải thích những thứ như phân bổ bộ nhớ.
dùng2616742

Không có các lớp cấp cao nhất tĩnh trong java
Andremoniy
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.