Глобальные переменные в Java


217

Как вы определяете глобальные переменные в Java?


20
Можете ли вы сказать нам, почему вы хотите определить глобальные переменные в Java?
Адам Пейнтер

44
Доступ к переменной из-за пределов класса
aTJ

5
Возможно, вам следует отредактировать свой вопрос, включив в него пример кода, иллюстрирующий именно то, что вы хотите. Это поможет нам порекомендовать лучшее решение.
Адам Пейнтер

7
@ Адам: я должен быть в состоянии изменить значение переменной в одном классе из другого класса.
аи

2
Вы не В Java нет глобальных переменных.
маркиз Лорн

Ответы:


261

Для определения глобальной переменной вы можете использовать статическое ключевое слово

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

теперь вы можете получить доступ к a и b из любого места, позвонив

Example.a;

Example.b;

6
«Global» - это название класса.
Джером

12
Будьте осторожны при этом - когда класс Global выгружается, переменные будут неопределенными null. Если вы продаете свое приложение, это произойдет рано или поздно, и вы будете искать ошибки везде, но не там ....
user387184

10
staticКлючевое слово делает переменные глобально доступной, при загруженном их класс.
sjas

22
О выгрузке классов: если существует какая-либо сильная цепочка ссылок от любого корня GC до экземпляра Global или его дочерних элементов или какая-либо ссылка времени компиляции из загруженного и не выгружаемого класса в Global, то объект Class относительно Global сильно достижимый, и, следовательно, так же ClassLoader, который загрузил Global; что делает невозможным выгрузку Global (поскольку выгрузка класса может произойти только после того, как GC полностью удалит любую сильную ссылку на ClassLoader, который загрузил данный класс). Если у вас нет ссылок вообще, как разгрузка может быть проблемой ???
Бруно Рейс

4
@Abi Я бы посоветовал вам переименовать ваш класс Globalв другое ( TestClass?), Чтобы у людей не сложилось впечатление, что существует такая вещь, как Globalключевое слово Java. Лучше в безопасности, чем потом сожалеть :)
Николас Ринаудо

53

Вы не Это по замыслу. Ты не должен делать это, даже если бы мог.

При этом вы можете создать набор открытых статических членов в классе с именем Globals.

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

но вы действительно не должны :). Серьезно .. не делай этого.


6
Тогда каков лучший способ, которым я могу объявить константы, чтобы все методы класса могли получить к ним доступ?
Олстон

6
Сообщения такого рода - причина, по которой новички разрабатывают глобальную переменную фобию, и затем мы видим, что разрабатываются всевозможные вопиющие методы, чтобы обойти табу глобальной переменной, но достичь того же эффекта.
Евгений Сергеев

40
Голосуй за то, чтобы сказать: «Не делай этого». без объяснения или ссылки на объяснение почему.
Джефф МакКьюн

4
@JeffMcCune: чтобы сделать ваше заявление более понятным, «не делайте этого» - это на самом деле фигня. Делай это, когда это полезно. Например, я должен отладить свой код с помощью некоторого IAbstractLoggerBullshit и, конечно, System.err не работает в этой сверхинженерной среде. Я не могу засорять свой код, передавая дерьмо логгера между сотнями бесполезных классов адаптеров.
Джо Со

6
Я собираюсь сделать это.
Плавающая солнечная

40

Другой способ - создать такой интерфейс:

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

Любой класс, который должен использовать их, должен только реализовать интерфейс:

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

Мне интересно, почему у этого ответа (до моего) нет повышающих голосов. Разве это не дает разумного альтернативного ответа на вопрос, который дают все остальные ответы?
M_M

12
«Эффективная Java» Джошуа Блоха, глава 4: Классы и интерфейсы, пункт 19: используйте интерфейсы только для определения типов «Постоянный шаблон интерфейса - это плохое использование интерфейсов». Эту книгу стоит прочитать! :)
MariuszS

1
Кроме того, из JDK 1.5+ вы можете использовать статический импорт для ваших глобальных переменных, реализация не требуется.
MariuszS

9
.... Правильно, это на самом деле ничего не объясняет, просто говорит, что в какой-то книге сказано, что это плохо.
linkhyrule5

14
Вот цитата для вас. Oracle говорит: «Чтобы обойти это, люди иногда помещают статические члены в интерфейс и наследуют от этого интерфейса. Это плохая идея. На самом деле, это настолько плохая идея, что для нее есть название: Constant Interface Antipattern (см. пункт «Эффективная Java» 17). Проблема в том, что использование классом статических членов другого класса является простой деталью реализации. Когда класс реализует интерфейс, он становится частью открытого API класса. Детали реализации не должны попадать в публичные API. "
Jolta

23

Вам лучше использовать внедрение зависимостей:

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" немного сбивает с толку :-). Что-то вроде «Параметры» было бы более подходящим, так как это не обязательно Global.
Марк Питерс

12

Множество хороших ответов, но я хочу привести этот пример, так как он считается более правильным способом доступа к переменным класса другим классом: с использованием методов получения и установки.

Причина, по которой вы используете геттеры и сеттеры таким образом, а не просто делаете переменную общедоступной, заключается в следующем. Допустим, ваш var будет глобальным параметром, который вы НИКОГДА не хотите, чтобы кто-то изменил во время выполнения вашей программы (в случае, когда вы разрабатываете код с командой), что-то вроде, возможно, URL-адреса веб-сайта. Теоретически это может измениться и может использоваться много раз в вашей программе, поэтому вы хотите использовать глобальную переменную, чтобы иметь возможность обновлять все сразу. Но вы не хотите, чтобы кто-то другой вошел и изменил эту переменную (возможно, даже не осознавая, насколько это важно). В этом случае вы просто не включаете метод установки, а только метод получения.

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

В Java нет глобальной переменной

Тем не менее, у нас есть staticключевое слово, и это все, что нам нужно. Ничто не существует вне класса в Java. staticКлючевое слово представляет собой переменный класс , который, в отличие от переменного экземпляра, имеет только одну копии и которая выходит за пределы во всех экземплярах этого класса , созданных, а это значит , что его значение может быть изменено и доступом во всех случаях , в любой момент.

Если вам нужна глобальная переменная, к которой можно получить доступ за пределами области действия, то эта переменная вам нужна, но ее область действия существует только там, где находится класс, и это будет все.


9

По правде говоря, нет понятия «ГЛОБАЛ» в Java-программе

Тем не менее, в вашем вопросе есть доля правды, потому что в некоторых случаях вы захотите запустить метод в любой части программы. Например, метод random () в приложении Phrase-O-Matic: этот метод должен вызываться из любой части программы.

Таким образом, для того, чтобы удовлетворить такие вещи, как Выше «Нам нужны глобальные переменные и методы»

ОБЪЯВИТЬ ПЕРЕМЕННОЕ ГЛОБАЛЬНЫМ.

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

ОБЪЯВИТЬ МЕТОД КАК ГЛОБАЛЬНО .

 1. Mark the method as public static While declaring.

Поскольку я объявил глобальные переменные и метод как статические, вы можете вызывать их где угодно, просто с помощью следующего кода

ClassName.X

ПРИМЕЧАНИЕ . X может быть либо именем метода, либо именем переменной согласно требованию, а ClassName - это имя класса, в котором вы их объявили.


9

Ничто не должно быть глобальным, кроме констант.

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

Поместите это в свой основной класс. В других файлах .java используйте его через:

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

Убедитесь, что когда вы перемещаете свой код с пола режущей комнаты и в выпуске вы удаляете или комментируете эту функцию.

Если у вас есть метод рабочей лошадки, например, рандомизатор, я предлагаю создать пакет «Toolbox»! У всех кодеров должен быть один, тогда, когда вы захотите использовать его в .java, просто импортируйте его!


5

В Java нет такой вещи как действительно глобальная переменная. Каждая статическая переменная должна принадлежать какому-либо классу (например, System.out), но когда вы определили, в какой класс она будет входить, вы можете ссылаться на нее из любого места, загруженного одним и тем же загрузчиком классов.

Обратите внимание, что статические переменные всегда должны быть защищены при обновлении, чтобы избежать состояния гонки.


1
Java не предоставляет глобальную переменную функционально, но если вы хотите иметь концепцию глобальной переменной, мы можем использовать статическое ключевое слово
Abi

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

Таким образом, вы можете получить к ним доступ GlobalClass.xиGlobalClass.s


2
public class GlobalImpl {   

 public static int global = 5;

}

Вы можете позвонить куда угодно

GlobalImpl.global // 5

1

Как вы, вероятно, догадались из ответа, в Java нет глобальных переменных, и единственное, что вы можете сделать, - это создать класс со статическими членами:

public class Global {
    public static int a;
}

Вы можете использовать его в Global.aдругом месте. Однако, если вы используете Java 1.5 или выше, вы можете использовать import staticмагию, чтобы она выглядела еще более как настоящая глобальная переменная:

import static test.Global.*;

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

И вуаля !

Теперь это далеко не лучшая практика, так что вы можете видеть в рекламе: не делайте этого дома


1

В Java нет глобальных переменных, но есть глобальные классы с открытыми полями. Вы можете использовать функцию статического импорта в Java 5, чтобы она выглядела почти как глобальные переменные.


1

Вообще Глобальная переменная (я полагаю, вы сравниваете ее с C, Cpp) определяют как public static final

лайк

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

ENUM также полезны в таком сценарии:

Для примера Calendar.JANUARY)


Должна ли глобальная переменная быть конечной? Зачем?
Конерак

1
«окончательный» означает «постоянный», так что это глобальная константа.
duffymo

1
нет, вот что означает глобальная переменная, если вы хотите поделиться этой переменной и изменить данные, а затем просто удалить, finalно это, безусловно, зависит от того, как вы хотите поделиться, где вы используете и все,
Джигар Джоши

Какой тип CODEв этом примере? Где это определено?
M_M

Также обратите внимание: CODE присутствует во всех заглавных буквах, так как это обычная нотация Java для использования всех заглавных букв для переменных, которые вы объявляете как окончательные, и которые не предназначены для изменения в течение программы.
Дэн Сиборовский - MSFT

1

Создание независимого файла, например. Example.java, чтобы использовать 1-е решение, просто отлично. Вы можете сделать это также в приложении, если, например, глобальные переменные являются особенными для вашего текущего приложения и т. Д .:

Создайте класс в начале и объявите свои переменные там:

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

Затем вы можете получить доступ к этим переменным - используя их как «Globals.month_number» и т. Д. - из любого места в вашем приложении.


Вместо понижения голоса, скажите, пожалуйста, что не так с этим решением? Я использую это на постоянной основе, и это наиболее удобный. Так что я не могу поступить иначе, если рассматривать это отрицательное мнение как личную вещь или просто сделанное глупым человеком.
Апостолоса

1

Если вам нужно обновить глобальное свойство, в качестве глобальной переменной можно использовать простой класс-оболочку getter / setter. Типичный пример показан ниже.

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

Исходя из концепции, глобальные переменные, также известные как переменные экземпляра, являются переменными уровня класса, то есть они определены внутри класса, но вне методов. Чтобы сделать их полностью доступными и использовать их, предоставьте ключевое слово static. Так что, если я пишу программу для простой арифметической операции, и для нее требуется пара чисел, то две переменные экземпляра определяются следующим образом:

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

Более того, использование статического ключевого слова перед переменными экземпляра позволяет нам не указывать типы данных для одних и тех же переменных снова и снова. Просто напишите переменную напрямую.


1
В Java нет глобальных переменных; они также не известны как переменные экземпляра; определение их как « staticне делает их доступными полностью». Первый абзац это чепуха. Пример плохой практики.
маркиз Лорн

0

В общем, Java не имеет глобальных переменных. За исключением локальных переменных, все переменные входят в область действия любого класса, определенного в программе. Мы можем иметь статические переменные, чтобы иметь область видимости глобальных переменных.


0

без staticэтого тоже возможно

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

Объектно-ориентированное программирование построено с пониманием того, что область видимости переменных тесно связана с объектом класса, который инкапсулирует эти переменные.

Проблема с созданием «глобальных переменных» заключается в том, что это не является отраслевым стандартом для Java. Это не отраслевой стандарт, поскольку он позволяет нескольким классам манипулировать данными асинхронно, если вы используете многопоточное приложение, это становится немного сложнее и опаснее с точки зрения безопасности потоков. Существуют и другие причины, по которым использование глобальных переменных неэффективно, но если вы хотите этого избежать, я предлагаю вам обратиться к аспектно-ориентированному программированию .

Аспектно-ориентированное программирование устраняет эту проблему, возлагая на родительский класс ответственность за область действия через что-то, называемое «советами», что добавляет дополнительное поведение к коду без его фактического изменения. Он предлагает решения для сквозных задач или использования глобальных переменных.

Spring - это Java-фреймворк, использующий AOP, и хотя он традиционно используется для веб-приложений, базовое приложение может использоваться повсеместно в Java-фреймворке (включая 8.0). Это может быть направление, которое вы хотите изучить больше.


0

Понимание проблемы

Я рассматриваю квалификацию глобальной переменной как переменную, к которой можно обращаться и изменять в любом месте кода, не заботясь о статическом вызове / вызове экземпляра или передаче любой ссылки из одного класса в другой.

Обычно, если у вас есть класс А

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

и хотите получить доступ и обновить myvarв классе B,

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

Теперь вы можете получить уникальный экземпляр Global в любом месте с помощью:

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
Что этот ответ добавляет, что другие ответы нет? Я не вижу никакой "новой" ценности в этом ответе.
EWit

-2

Для определения глобальной переменной вы можете использовать статическое ключевое слово

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

теперь вы можете получить доступ к a и b из любого места, позвонив

Tools.a;
Tools.b;

Yoy правы ... особенно в J2ME ... Вы можете избежать NullPointerException, поместив в свой конструктор MidLet (proggy initialization) эту строку кода:

new Tools();

Это гарантирует, что Инструменты будут размещены перед любой инструкцией, которая их использует.

Это оно!


3
Хм ... Извините, но что это добавляет, что еще не охвачено существующими ответами?
Мистик

Возможно, вы правы .. но этот ответ объясняет такие вещи, как распределение памяти.
user2616742

В java нет статических классов верхнего уровня
Andremoniy
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.