Java Warum ergibt dieser String-Vergleich true?

Sebuss

Newbie
Registriert
Nov. 2010
Beiträge
7
Abend.

Habe mir gerade ein Beispiel aus den Oracle-Tutorials angeschaut und an folgender Stelle frage ich mich wie das sein kann:

Code:
if ("progress" == evt.getPropertyName())

Ist aus dem Beispiel "ProgressBarDemo" aus der Methode "public void propertyChange(PropertyChangeEvent)". Download hier.

Ich dachte immer das wenn ein String erstellt wird immer neues Objekt erstellt , weshalb der konstante String "progress" eigentlich doch nie identisch mit dem Objekt sein dürfte das über den Getter kommt. Ich kann aber versichern das es irgendwann mal true liefert.

Wer weiß warum?

Grüße und danke
 
Ich habe mir das Projekt jetzt nicht angesehen, aber eine Funktion wie evt.getPropertyName() kann natürlich auch einen String zurückgeben.
 
weil eben nicht immer ein neues objekt erstellt wird. immerhin ist string immutable (unveränderlich als objekt). dasselbe phänomen gibts auch bei zahlen. so klappt == bis zu einer gewissen zahl, aber größeren nicht mehr.

das ganze dient dazu, nicht übermäßig viele objekte in den speicher zu legen (die eh gleich sind und sich nicht ändern). ist meines wissens keine notwendigkeit für eine jvm, die sun/oracle macht es halt.

EDIT: das ganze hat mit autoboxing zu tun, bei mehr interesse: http://bexhuff.com/2006/11/java-1-5-autoboxing-wackyness
 
Zuletzt bearbeitet:
Der Compiler sammelt alle direkt im Quellcode stehende Strings in einem String-Pool.

Wenn im Quelltext der gleiche String an verschiedenen Stellen vorkommt, wird dann dasselbe Objekt (aus dem String-Pool) verwendet.

Daher ergibt der Vergleich der Speicherstelle mittels "==" dann auch true.

Meine Vermutung ist, das der String der PropertyName schon zur Compilezeit feststeht (also irgendwo im Quelltext steht) und daher das String-Objekt aus dem String-Pool verwendet wird. Genauso wird für "progress" das String-Objekt aus dem String-Pool verwendet.
 
@ManOki: Danke für den Link, hat sehr geholfen und mich zu ein paar Tests angeregt.

Code:
package tests.string.vergleich;

public class Test1 {
	
	public static boolean subVergleich(String s1, String s2) {
		return s1==s2;
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		//block #1
		String s1 = "hallo"; System.out.println("String s1 = \"hallo\"");
		String s2 = "hallo"; System.out.println("String s2 = \"hallo\"");
		System.out.println("\"hallo\"==\"hallo\": "+("hello"=="hello")); //true
		System.out.println("\"hallo\"==s1: "+("hello"==s1)); //false
		System.out.println("\"hallo\"==s2: "+("hello"==s2)); //false
		System.out.println("s1==s2: "+(s1==s2)); //true		
		System.out.println();
		
		//block #2
		s1 = "hello"; System.out.println("s1 = \"hello\"");
		s2 = "hello"; System.out.println("s2 = \"hello\"");
		System.out.println("\"hello\"==\"hello\": "+("hello"=="hello")); //true
		System.out.println("\"hello\"==s1: "+("hello"==s1)); //true
		System.out.println("\"hello\"==s2: "+("hello"==s2)); //true
		System.out.println("s1==s2: "+(s1==s2)); //true		
		System.out.println();
		
		//block #3
		System.out.println("subvergleich(s1, s2): "+subVergleich(s1, s2)); //true
		System.out.println();
		
		//block #4
		s2 = s1.toString(); System.out.println("s2 = s1.toString()");
		System.out.println("\"hello\"==s2: "+("hello"==s2)); //true
		System.out.println("s1==s2: "+(s1==s2)); //true
		System.out.println();
		
		//block #5
		s1 = new String("hallo"); System.out.println("s1 = new String(\"hallo\")");
		s2 = new String("hallo"); System.out.println("s2 = new String(\"hallo\")");
		System.out.println("\"hallo\"==s1: "+("hello"==s1)); //false
		System.out.println("\"hallo\"==s2: "+("hello"==s2)); //false
		System.out.println("s1==s2: "+(s1==s2)); //false		
		System.out.println();
		
		//block #6
		Object o = new Object();
		System.out.println(o.toString()==o.toString()); //false
	}

}
 
Genau, das liegt am String-Pool. Noch eine Anmerkung dazu zum Verständnis:

Während

Code:
if ("progress" == evt.getPropertyName())

true zurückliefern wird, solange dieser String auch tatsächlich aus dem evt.getPropertyName() zurückkommt, würde

Code:
if(new String("progress") == evt.getPropertyName())

false zurückliefern - denn durch die Benutzung des Konstruktors wird tatsächlich ein neuer Pointer angelegt und nicht der aus dem String-Pool benutzt.

Durch dieses meiner Meinung relativ verwirrende Verhalten sollte man daher in den meisten Fällen die equals()-Methode benutzen, es sei denn man hat einen spezifischen Grund auf tatsächliche Gleichheit der Pointer zu prüfen.
 
Man kann übrigens Strings auch manuell dem Pool hinzufügen, um den Identity-Vergleich zu ermöglichen:

Code:
if(new String("progress").intern() == evt.getPropertyName())

Man sollte aber schon sehr genau wissen, was man tut. Die Anwendungsfälle sollten sich sehr in Grenzen halten bzw. es bessere Alternativen geben.

Gerade für ein Tutorial halte ich den Einsatz des == Operators für einen String-Vergleich als fragwürdig. Ich würde auch empfehlen equals() zu verwenden.

Code:
if ("progress".equals(evt.getPropertyName())
 

Ähnliche Themen

Zurück
Oben