2015-06-14 2 views
19

Wie kompiliert das ohne Fehler? Nach meinem Verständnis überprüft der Compiler den Typ der Variablen (in diesem Fall String), dann sieht er, ob der Typ des Ausdrucks auf der rechten Seite dem Typ der Variablen entspricht (oder zumindest ein Subtyp, aber bleiben wir beim einfachen Fall mit die String Klasse, da es endgültig ist).Warum wird die Initialisierung einer Variablen in einen Zuweisungsausdruck [String x = (x = y)] kompiliert?

public class InitClass { 
    public static void main(String[] args) { 
    String str = (str = "hello"); 
    System.out.println(str); 
    } 
} 

Meine Frage ist, wie funktioniert str = "hello" kompilieren? Ist dem Compiler bereits bekannt, dass str vom Typ String sein sollte?

+0

(str = "Hallo") gibt die Zeichenfolge "Hallo" zurück. Eclipse rät von der Nachricht ab: "Die Zuweisung zur Variablen str hat keine Auswirkung" – LeTex

+3

@LeTex Ich setze Eclipse generell strenger und melde dies als Fehler anstatt als Warnungen. Ich sehe keinen Grund für jemanden, Konstrukte wie diese zu verwenden, obwohl sie von der JLS erlaubt sind. – biziclop

+2

Eine dieser interessanten Fragen, bei denen man denkt, "wer schreibt Code wie diesen und warum". Rein akademisch, sicher? – TEK

Antwort

15

Wenn ein assignment expression

Erste Auswertung der linke Operand wird eine Variable zu erzeugen ausgewertet. Wenn diese Auswertung abrupt abgeschlossen wird, wird der Zuweisungsausdruck aus dem gleichen Grund abrupt beendet. der rechte Operand wird nicht ausgewertet und keine Zuordnung erfolgt.

Das erzeugt die Variable str. Dann

Sonst wird der rechte Operand ausgewertet. Wenn diese Auswertung abrupt abgeschlossen wird, wird der Zuweisungsausdruck aus dem gleichen Grund abrupt abgeschlossen, und es findet keine Zuweisung statt.

In Ihrem Beispiel ist der rechte Operand selbst ein weiterer Zuweisungsausdruck. So wird str, der rechte Operand des Zuweisungsoperators, erneut ausgewertet, um eine Variable str zu erzeugen. Dann

Andernfalls wird der Wert des rechten Operanden an die Typ der linken Variable konvertiert wird, wird auf den Wert gesetzt Umwandlung unterworfen (§5.1.13) an den entsprechenden Standardwert (nicht ein Extended-Exponent Wert eingestellt), und das Ergebnis der Konvertierung ist in der Variablen gespeichert.

So "hello" in str gespeichert. And since

Zur Laufzeit das Ergebnis der Zuweisungsausdruck ist der Wert von die Variable nach der Zuweisung aufgetreten ist. Das Ergebnis eines Zuweisungsausdrucks ist selbst keine Variable.

das Ergebnis der Zuordnung von "hello" zu str ist der Wert "hello", wird dieser Wert wieder in str gespeichert.

0

Was zuerst passiert, ist, dass der Compiler den Typ der Referenz identifiziert, dann wissend, dass eine String-Zuweisung "Hallo" zu Str ist gültig.

5

Ihr Fall entspricht

String str; 
str = (str = "hello"); 

Obwohl die Zuordnungen lustig suchen, gibt es nichts konzeptionell falsch.

Dennoch ist eine variable Initialisierung, die sich selbst referenziert, offensichtlich keine gute Idee. Der Compiler wird versuchen, ihn in Situationen zu markieren, in denen ein Programmierfehler wahrscheinlich ist; der Compiler schafft es manchmal nicht; und kann auch einige Male über Bord gehen.

Eine lokale Variable hat eine strengere Anforderung (als eine Feldvariable) - sie muss zuerst zugewiesen werden, bevor ihr Wert verwendet wird. Zum Beispiel wird dies nicht kompiliert, weil die lokale Variable gelesen wird, bevor sie zugewiesen wird.

String str; // local variable 
str = str; // error, try to read `str` before it's assigned 

Eine Feldvariable hat immer einen Standardanfangswert; doch der Compiler prüft offensichtlich programer Fehler

int x = x+1; // error. x is field variable. 

Aber es ist nicht katastrophal, wenn eine solche Überprüfung fehlschlägt, da x Wert 0 vor explizite Zuweisung hat

int x; 
{ x=x+1; } // ok. x==0, then x==1 after assignment 

Wenn jedoch xfinal ist, wird der Code oben schlägt fehl, weil der Compiler eine eindeutige Zuordnung von x zuerst vor dem Lesen x erfordert, die gleiche Voraussetzung für eine lokale Variable. Aber diese Prüfung kann umgangen werden, weil es unmöglich ist, sie zu analysieren und zu verhindern, vollständig für Feldvariablen

final int x = (this).x+1; // compiles! 

In einigen Fällen geht der Compiler über Bord, verhindert legit Fälle Verwendung Lambda beteiligt

Runnable r1 =()->System.out.println(r1); // r1 is a field variable 

Es gibt nichts, konzeptionell problematisch in diesem Anwendungsfall; es kann von (this). auch umgangen werden.

+1

Der letzte Teil Ihrer Antwort ist sehr interessant, +1 – user2336315

Verwandte Themen