#define в Java


74

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

Швидкий пошук google каже, що цього немає, але хтось може сказати мені, чи існує щось подібне в Java? Я намагаюся зробити свій код більш читабельним.

Замість цього myArray[0]я хочу мати можливість писати, myArray[PROTEINS]наприклад.


9
У сучасному C ++ для цього слід використовувати набрану константу, а не #define
Піт Кіркхем,

2
Так, #define - це стиль С. У C ++ використовуйте замість цього const. Див. Книгу Скотта Мейєрса "Ефективний C ++", пункт 1.
Джабба,

Відповіді:


100

Ні, тому що немає попереднього компілятора. Однак у вашому випадку ви могли б досягти того ж, що наступним:

class MyClass
{
    private static final int PROTEINS = 0;

    ...

    MyArray[] foo = new MyArray[PROTEINS];

}

Компілятор помітить, що PROTEINSніколи, ніколи не може змінитися, і тому вбудує його, що є більш-менш тим, що ви хочете.

Зверніть увагу, що модифікатор доступу до константи тут неважливий, тому він може бути publicабо protectedзамість приватного, якщо ви хочете повторно використовувати одну і ту ж константу в декількох класах.


43

Місце для коментарів замале, тому ось вам трохи більше інформації про використання 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);
    }
}

Скомпілюйте їх і запустіть тест, який надрукує:

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допомогою примітивів, що використовується в звичайній ifумові Java та обчислюється, falseпризведе до того, що компілятор вилучить байтовий код для операторів у ifблоці (вони не генеруються).

private static final boolean DEBUG = false;

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

Код на "... код тут ..." не буде компілюватися в байт-код. Але якби ви змінили DEBUGна, trueто це було б.


2
Однозначно +1 лише за зусилля!
Andreas Dolk,

Просто хочу додати, що Java не робить те ж саме для enums.
Seyed Jalal Hosseini

5
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

Java не має загальної defineдирективи препроцесора.

У випадку з константами рекомендується оголосити їх такими static finals, як у

private static final int PROTEINS = 100;

Такі оголошення будуть вкладені компіляторами (якщо значення є константою часу компіляції).

Зауважте також, що загальнодоступні статичні поля остаточної константи є частиною загальнодоступного інтерфейсу, і їх значення не повинні змінюватися (як їх вкладає компілятор). Якщо ви все-таки зміните значення, вам потрібно буде перекомпілювати всі джерела, на які посилається це поле константи.


Ну, приватне static finals насправді не є частиною загальнодоступного інтерфейсу. :) Адже public static finalsце правда.
Bombe

@Mombe, правильно. Спочатку я писав це як загальнодоступне, але потім змінив, не оновлюючи відповідь.
notnoop

3

Існує препроцесор для Java, який надає директиви, такі як #define, #ifdef, #ifndef та багато інших, наприклад, команда PostgresJDBC використовує його для створення джерел для різних випадків та не дублювання коду.


1

Найбільш читаються рішенням є використання статичного імпорту . Тоді вам не потрібно буде користуватися 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

Найпростіша відповідь - "Немає прямого методу отримання, оскільки немає попереднього компілятора", але ви можете зробити це самостійно. Використовуйте класи, а потім визначайте змінні як final, щоб їх можна було вважати постійними у програмі.
Не забудьте використовувати final і змінну як загальнодоступні або захищені не приватні, інакше ви не зможете отримати до них доступ поза межами цього класу.



0

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

Він має плагіни Maven та Gradle.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.