#define в Java

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

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

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

7 ответов

Решение

Нет, потому что нет прекомпилятора.

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

class MyClass
{
    private static final int PROTEINS = 0;

    ...

    MyArray[] foo = new MyArray[PROTEINS];

}

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

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

Слишком мало места для комментариев, так что вот вам дополнительная информация об использовании 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 тогда было бы.

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" в последнем цикле компиляции!

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

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

private static final int PROTEINS = 100;

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

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

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

Препроцессор Manifold, реализованный как плагин компилятора javac, предназначен исключительно для условной компиляции исходного кода Java. Он использует знакомый стиль директив C/C++: #define, #undef, #if, #elif, #else, #endif, #error. и # предупреждение.

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

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

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

package ConstantPackage;

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

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

import static ConstantPackage.Constant.PROTEINS;

public class StaticImportDemo {

    public static void main(String[]args) {

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

    }
}

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

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

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

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

Другие вопросы по тегам