PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : [JAVA] static block und konstanten


Gast
2008-11-22, 23:56:42
public calss test {
static {
makeSomeThing();
}

private static void makeSomeThing() {
System.out.println(ONE); // Output: 1
System.out.println(STRING); // Output: string
System.out.println(STRINGS[1]); // NullPointer
}

private static final int ONE = 1;
private static final String STRING = "string";
private static final String[] STRINGS= {
"string_0",
"string_1",
"string_2"
};
}

warum bekomme ich bei der dritten ausgabe eine nullpointer exception?

Gast
2008-11-22, 23:59:24
achja:

die anti-bot-verifikation fragt mich:
"How many bytes does a kilobyte contain?"

ich antworte: 1024


und es kommt das diese antwort falsch sei??

Laz-Y
2008-11-23, 00:05:27
Seltsamer Code...
Naja, jedenfalls musst Du zuerst die Variable STRINGS initialisieren, bevor Du drauf zugreifst. Sprich zuerst private static final String[] STRINGS= ... und erst dann makeSomeThing();

Gast
2008-11-23, 00:09:59
warum ist der code seltsam?

aber das ich das mit der reihenfolge beheben kann, ist mir natürlich klar.
nur nicht warum das bei string objekten kein problem ist, aber scheinbar bei arrays von strings.

sorry das es nicht klar ersichtlich war...

Nvidia5
2008-11-23, 08:56:27
public class test {

private static void makeSomeThing() {
System.out.println(ONE); // Output: 1
System.out.println(WORD); // Output: string
System.out.println(STRINGS[1]); // NullPointer
}

private static final int ONE = 1;
private static final String WORD= "string";
private static final String[] STRINGS= {
"string_0",
"string_1",
"string_2"
};

public static void main(String[] args) {
makeSomeThing();
}
}

Das ist einmal der überarbeitete Code.
Dieser funktioniert, du musst ledeglich die HTML Tags noch rauslöschen.

Senior Sanchez
2008-11-23, 09:41:52
achja:

die anti-bot-verifikation fragt mich:
"How many bytes does a kilobyte contain?"

ich antworte: 1024


und es kommt das diese antwort falsch sei??

Ist es auch, da es 1000 sind.
Aber diese Diskussion wurde schon episch geführt. Irgendwo hier im Forum findste dazu garantiert etwas-

DocEW
2008-11-24, 11:10:56
Interessant!
Anscheinend werden einfach String-Literale sofort initialisiert und Arrays erst später..?
Ich habe mal hier (http://java.sun.com/docs/books/jls/second_edition/html/classes.doc.html#287406) ein bisschen gelesen, aber auf die Schnelle keine Antwort gefunden.

Abnaxos
2008-11-30, 12:58:39
Wenn primitive Typen oder Strings static final deklariert sind, werden sie als Konstanten direkt in den Code eincompiliert. Das kann man auch sehen, wenn man das kompilat wieder disassembliert:

$ javap -classpath . -c -private test
[...]
private static void makeSomeThing();
Code:
0: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
3: iconst_1
4: invokevirtual #3; //Method java/io/PrintStream.println:(I)V
7: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
10: ldc #4; //String string
12: invokevirtual #5; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
15: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
18: getstatic #6; //Field STRINGS:[Ljava/lang/String;
21: iconst_1
22: aaload
23: invokevirtual #5; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
26: return
[...]

Zeile 0: Den Inhalt des statischen Felds System.out auf den Stack legen, die Int-Konstante 1 auf den Stack legen, Methode println() aufrufen.

Zeile 7: Den Inhalt des statischen Felds System.out auf den Stack legen, den String #4 aus dem String-Konstantenpool holen, Methode println() aufrufen.

Zeile 15: Den Inhalt des statischen Felds System.out auf den Stack legen, den Inhalt des statischen Felds STRINGS auf den Stack legen, die Int-Konstante 1 auf den Stack legen, das Array-Element laden (dadurch werden die 1 und das String-Array vom Stack entfernt und STRING[1] auf den Stack gelegt), die Methode println() aufrufen.

Monger
2008-11-30, 14:03:23
Interessant!
Anscheinend werden einfach String-Literale sofort initialisiert und Arrays erst später..?


String Literale werden grundsätzlich interned. "intern" heißt: die werden vorgecached, da die vermutlich sehr häufig verwendet werden, und man so ein bißchen die Performance verbessert.

Das gilt für alle Literale - nicht nur statische Attribute, sondern auch Variablen.

Das ist übrigens auch der Grund, weshalb

String stringA = "Blubb";
String stringB = "Blubb";

...
stringA == stringB
als Ergebnis "wahr" ergibt, dies hier hingegen:

String stringA = "Blubb"
String stringB = "Blu"
stringB += "bb"

...
stringA == stringB

"false" zurückgibt. Direkte Objektreferenzvergleiche funktionieren direkt mit Literalen, aber nicht mit Strings die zur Laufzeit erzeugt werden. Deshalb soll man Strings NIEMALS mit == vergleichen, sondern immer mit Equals.

(Andere Sprachen machen böses Operator Overloading, deshalb funktioniert es da manchmal doch! ;) )

patermatrix
2008-11-30, 14:54:48
@ Monger
Besteht aus Performancesicht dann überhaupt noch ein Unterschied zu final? (Den ersten Fall vorausgesetzt, natürlich.)

Monger
2008-11-30, 15:21:20
@ Monger
Besteht aus Performancesicht dann überhaupt noch ein Unterschied zu final? (Den ersten Fall vorausgesetzt, natürlich.)

Final ist wohl nochmal ein ganz eigener Fall für sich. Da finale Variablen und Attribute sich garantiert nicht ändern, kann der Compiler da wohl Optimierungen drauf ansetzen die bei normalen Variablen nicht gehen. Nicht nur deshalb, sondern auch wegen des robusteren Designs ist es deshalb in Java vernünftig, Variablendeklarationen als final zu deklarieren (also auch innerhalb einer Methode, oder in deren Signatur) die es auch tatsächlich sind.

(btw. , finale Methoden bzw. Klassen haben absolut nichts mit finalen Variablen und Attributen zu tun)

Abnaxos
2008-11-30, 15:24:50
final macht aus Performance-Sicht nie einen Unterschied. Auf Bytecode-Ebene sieht man das nicht (es sei denn, dieses Inlining von Konstanten wurde gemacht), bei interpretiertem Code spielt es also keine Rolle. Wird der Code als performance-kritisch identifiziert und zu Maschinencode compiliert, wird extrem aggressiv optimiert, HotSpot (im Falle einer Sun-JVM) braucht hier keinen Tipp zur Optimierung, der merkt selber, was er tun kann und was nicht. Manchmal ist er ein wenig zu aggressiv, weshalb er manchmal einen Tipp braucht, wo er nicht ganz so aggressiv optimieren soll: Eine Deklaration als volatile.

Zum Inlining von Konstanten: Könnte man sich heute noch anders entscheiden, würde man das wohl tun. Es macht mehr Probleme als etwas anderes, wurde aber in Javas jungen Jahren (leider) in die JLS aufgenommen, jetzt kriegt man es nicht mehr weg ...