#define in Java

74

Ich fange an, in Java zu programmieren, und frage mich, ob das Äquivalent zu C ++ #defineexistiert.

Eine schnelle Suche bei Google sagt, dass dies nicht der Fall ist, aber kann mir jemand sagen, ob es in Java etwas Ähnliches gibt? Ich versuche, meinen Code lesbarer zu machen.

Stattdessen myArray[0]möchte ich myArray[PROTEINS]zum Beispiel schreiben können .

Meir
quelle
9
In modernem C ++ sollten Sie dafür eine typisierte Konstante anstelle einer #define verwenden
Pete Kirkham
2
Ja, #define ist im C-Stil. Verwenden Sie in C ++ stattdessen const. Siehe Scott Meyers "Effective C ++" Buch, Punkt 1.
Jabba

Antworten:

99

Nein, weil es keinen Precompiler gibt. In Ihrem Fall könnten Sie jedoch Folgendes erreichen:

class MyClass
{
    private static final int PROTEINS = 0;

    ...

    MyArray[] foo = new MyArray[PROTEINS];

}

Der Compiler wird bemerken, dass PROTEINSsich dies niemals ändern kann, und wird es auch inline setzen, was mehr oder weniger das ist, was Sie wollen.

Beachten Sie, dass der Zugriffsmodifikator für die Konstante hier unwichtig ist. Er kann also publicoder protectednicht privat sein, wenn Sie dieselbe Konstante für mehrere Klassen wiederverwenden möchten .

Andrzej Doyle
quelle
43

Der Kommentarbereich ist zu klein, daher finden Sie hier weitere Informationen zur Verwendung von static final. Wie ich in meinem Kommentar zur Antwort von Andrzej sagte , nur primitiv und Stringwerden als Literale direkt in den Code kompiliert. Versuchen Sie Folgendes, um dies zu demonstrieren:

Sie können dies in Aktion sehen, indem Sie drei Klassen (in separaten Dateien) erstellen:

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

Kompilieren Sie diese und führen Sie Test aus, der Folgendes druckt:

Int    = 0
Value  = A

Ändern Sie nun, um Constantsfür jede Klasse einen anderen Wert zu haben, und kompilieren Sie einfach die Klasse Constants. Wenn Sie Testerneut ausführen (ohne die Klassendatei neu zu kompilieren), wird weiterhin der alte Wert für gedruckt, INT_VALUEjedoch nicht VALUE. Zum Beispiel:

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

Führen Sie den Test aus, ohne ihn neu zu kompilieren Test.java:

Int    = 0
Value  = X

Beachten Sie, dass jeder andere Typ, der mit verwendet static finalwird, als Referenz beibehalten wird.

Ähnlich wie bei C / C ++ #if/ #endifführt ein konstantes oder static finalmit Primitiven definiertes Literal , das in einer regulären Java- ifBedingung verwendet und ausgewertet wird, falsedazu, dass der Compiler den Bytecode für die Anweisungen innerhalb des ifBlocks entfernt (sie werden nicht generiert).

private static final boolean DEBUG = false;

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

Der Code unter "... Code hier ..." würde nicht in den Bytecode kompiliert. Aber wenn Sie DEBUGzu truedann wechseln würden, wäre es.

Kevin Brock
quelle
2
Auf jeden Fall eine +1 nur für die Mühe!
Andreas Dolk
Ich möchte nur hinzufügen, dass Java für enums nicht dasselbe tut .
Seyed Jalal Hosseini
5
static final int PROTEINS = 1
...
myArray[PROTEINS]

Normalerweise würden Sie "Konstanten" in die Klasse selbst einfügen. Beachten Sie außerdem, dass ein Compiler Verweise darauf optimieren darf. Ändern Sie ihn daher nur, wenn Sie alle verwendenden Klassen neu kompilieren.

class Foo {
  public static final int SIZE = 5;

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

Bearbeiten Zyklus ... SIZE=4. Kompilieren BarSie auch, weil Ihr Compiler im letzten Kompilierungszyklus möglicherweise gerade "4" geschrieben hat!

Extraneon
quelle
4

Java hat keine Allzweck- definePräprozessor-Direktive.

Bei Konstanten wird empfohlen, diese static finalswie in zu deklarieren

private static final int PROTEINS = 100;

Solche Deklarationen würden von den Compilern eingefügt (wenn der Wert eine Konstante zur Kompilierungszeit ist).

Bitte beachten Sie auch, dass öffentliche statische Endkonstantenfelder Teil der öffentlichen Schnittstelle sind und sich ihre Werte nicht ändern sollten (da der Compiler sie einfügt). Wenn Sie den Wert ändern, müssen Sie alle Quellen neu kompilieren, die auf dieses konstante Feld verweisen.

notnoop
quelle
Nun, privat static finals sind nicht wirklich ein Teil der öffentlichen Schnittstelle. :) Dafür public static finalsist das allerdings wahr.
Bombe
@ Mama, richtig. Ich habe es zunächst als öffentlich geschrieben, dann aber geändert, ohne die Antwort zu aktualisieren.
Notnoop
3

Es gibt einen Präprozessor für Java, der Anweisungen wie #define, #ifdef, #ifndef und viele andere bereitstellt. Das PostgresJDBC-Team verwendet ihn beispielsweise, um Quellen für verschiedene Fälle zu generieren und keinen Code zu duplizieren.

Igor Maznitsa
quelle
1

Die am besten lesbare Lösung ist der statische Import . Dann müssen Sie nicht verwenden AnotherClass.constant.

Schreiben Sie eine Klasse mit der Konstante als public staticFeld.

package ConstantPackage;

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

Verwenden Sie dann einfach den statischen Import, wo Sie die Konstante benötigen.

import static ConstantPackage.Constant.PROTEINS;

public class StaticImportDemo {

    public static void main(String[]args) {

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

    }
}

Weitere Informationen zum statischen Import finden Sie in dieser Frage zum Stapelüberlauf .

Md. Abu Nafee Ibna Zahid
quelle
0

Die einfachste Antwort lautet "Keine direkte Methode, um sie zu erhalten, da es keinen Pre-Compiler gibt". Sie können dies jedoch selbst tun. Verwenden Sie Klassen und definieren Sie Variablen als final, damit sie im gesamten Programm als konstant angenommen werden können.
Vergessen Sie nicht, final und variable als public oder protected not private zu verwenden, da Sie sonst nicht von außerhalb dieser Klasse darauf zugreifen können

Jitendra Nagar
quelle
0

Java Primitive Spezialisierungen Generator unterstützt /* with */, /* define */und /* if */ ... /* elif */ ... /* endif */Blöcke , die eine Art von Makro - Generation zu tun , in Java - Code in erwähnt, ähnlich wie Java-Kommentar-Präprozessor erlauben diese Antwort .

JPSG hat Maven- und Gradle-Plugins.

leventov
quelle
0

Der als Javac-Compiler-Plugin implementierte Manifold Preprocessor wurde ausschließlich für die bedingte Kompilierung von Java-Quellcode entwickelt. Es verwendet den bekannten C / C ++ - Direktivenstil: #define, #undef, #if, #elif, #else, #endif, #error. und #warning.

Es hat Maven und Gradle Plugins.

Pavlo Maistrenko
quelle