#define в Java - PullRequest
       62

#define в Java

66 голосов
/ 18 декабря 2009

Я начинаю программировать на Java, и мне интересно, существует ли эквивалент C ++ #define.

Быстрый поиск в Google говорит, что это не так, но может кто-нибудь сказать мне, если что-то подобное существует в Java? Я пытаюсь сделать мой код более читабельным.

Вместо myArray[0] Я хочу, например, написать myArray[PROTEINS].

Ответы [ 8 ]

88 голосов
/ 18 декабря 2009

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

class MyClass
{
    private static final int PROTEINS = 0;

    ...

    MyArray[] foo = new MyArray[PROTEINS];

}

Компилятор заметит, что PROTEINS никогда, никогда не изменится, и поэтому встроит его, что более или менее то, что вы хотите.

Обратите внимание, что модификатор доступа к константе здесь не важен, поэтому он может быть public или protected вместо private, если вы хотите повторно использовать одну и ту же константу в нескольких классах.

37 голосов
/ 18 декабря 2009

Слишком мало места для комментариев, так что здесь есть дополнительная информация для использования static final. Как я сказал в своем комментарии к ответу Анджей , только примитив и String скомпилированы непосредственно в код как литералы. Чтобы продемонстрировать это, попробуйте следующее:

Вы можете увидеть это в действии, создав три класса (в отдельных файлах):

public class DisplayValue {
    private String value;

    public DisplayValue(String value) {
        this.value = value;
    }

    public String toString() {
        return value;
    }
}

public class Constants {
    public static final int INT_VALUE = 0;
    public static final DisplayValue VALUE = new DisplayValue("A");
}

public class Test {
    public static void main(String[] args) {
        System.out.println("Int   = " + Constants.INT_VALUE);
        System.out.println("Value = " + Constants.VALUE);
    }
}

Скомпилируйте их и запустите Test, который печатает:

Int    = 0
Value  = A

Теперь измените Constants, чтобы иметь разные значения для каждого, и просто скомпилируйте класс Constants. При повторном выполнении Test (без перекомпиляции файла класса) он по-прежнему печатает старое значение для INT_VALUE, но не VALUE. Например:

public class Constants {
    public static final int INT_VALUE = 2;
    public static final DisplayValue VALUE = new DisplayValue("X");
}

Выполнить тест без перекомпиляции Test.java:

Int    = 0
Value  = X

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

Подобно C / C ++ #if / #endif, константный литерал или константа, определенная через static final с примитивами, используемая в обычном условии Java if и оцениваемая в false, заставит компилятор удалить байтовый код для операторов в блоке if (они не будут сгенерированы).

private static final boolean DEBUG = false;

if (DEBUG) {
    ...code here...
}

Код в "... код здесь ..." не будет скомпилирован в байт-код. Но если бы вы изменили DEBUG на true, тогда это было бы.

5 голосов
/ 18 декабря 2009
static final int PROTEINS = 1
...
myArray[PROTEINS]

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

class Foo {
  public static final int SIZE = 5;

  public static int[] arr = new int[SIZE];
}
class Bar {
  int last = arr[Foo.SIZE - 1]; 
}

Редактировать цикл ... SIZE=4. Также скомпилируйте Bar, потому что ваш компилятор, возможно, только что написал «4» в последнем цикле компиляции!

4 голосов
/ 18 декабря 2009

Java не имеет директивы препроцессора общего назначения define.

В случае констант рекомендуется объявить их как static finals, как в

private static final int PROTEINS = 100;

Такие объявления будут встроены компиляторами (если значение является константой времени компиляции).

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

3 голосов
/ 18 января 2018

Существует препроцессор для Java , который предоставляет директивы, такие как #define, #ifdef, #ifndef и многие другие, например, команда PostgresJDBC использует его для генерации источников для различных случаев и для того, чтобы не дублировать код. *

0 голосов
/ 08 апреля 2019

Генератор специализаций примитивов Java поддерживает блоки /* with */, /* define */ и /* if */ ... /* elif */ ... /* endif */, которые позволяют выполнять некую генерацию макросов в коде Java, подобно java-comment-препроцессору, упомянутому в этот ответ .

JPSG имеет плагины Maven и Gradle.

0 голосов
/ 02 января 2018

Большинство удобочитаемое решение использует Статический импорт . Тогда вам не нужно будет использовать AnotherClass.constant.

Напишите класс с константой в виде поля public static.

package ConstantPackage;

public class Constant {
    public static int PROTEINS = 1;
}

Тогда просто используйте Статический импорт там, где вам нужна постоянная.

import static ConstantPackage.Constant.PROTEINS;

public class StaticImportDemo {

    public static void main(String[]args) {

        int[] myArray = new int[5];
        myArray[PROTEINS] = 0;

    }
}

Чтобы узнать больше о статическом импорте, см. этот вопрос переполнения стека .

0 голосов
/ 30 мая 2017

Простейший ответ: "Нет прямого способа получить его, потому что нет прекомпилятора" Но вы можете сделать это самостоятельно. Используйте классы, а затем определите переменные как final , чтобы их можно было считать постоянными во всей программе
Не забудьте использовать final и variable как общедоступные или защищенные, а не private, иначе вы не сможете получить доступ к ним извне этого класса

...