Warum scheint String.intern() unterschiedliche Instanzen für gleiche Zeichenfolgen zurückzugeben?Java

Java-Forum
Guest
 Warum scheint String.intern() unterschiedliche Instanzen für gleiche Zeichenfolgen zurückzugeben?

Post by Guest »

Ich habe ein Verhalten von String.intern() beobachtet, das ich zu verstehen versuche. Es scheint der Dokumentation für diese Methode zu widersprechen.

Code: Select all

private static String buildSampleString() {
StringBuilder builder = new StringBuilder();
for (int i = 0; i < 10; i++) {
builder.append((char)(i + 'a'));
}
return builder.toString();
}

private static void performTest(String a) {
String b = buildSampleString().intern();
System.out.println("a vs. b: " + (a == b) + ", " + a.equals(b));
System.out.println(b + ": " + System.identityHashCode(b));
}

public static void main(String[] args) {
String a = buildSampleString();
performTest(a);
performComputation(); // see below for details
performTest(a);
}

Code: Select all

buildSampleString()
erzeugt bei jedem Aufruf neue, gleiche Zeichenfolgen. Eine dieser Instanzen, ein, wird während der gesamten Lebensdauer des Programms beibehalten. performTest(a) erstellt ein neues, b, interniert es und vergleicht es dann mit a (sowohl auf Identität als auch auf Gleichheit), und wie erwartet sind sie gleich, aber nicht identisch. Letzteres liegt daran, dass a nicht interniert wurde.
In der Dokumentation für String.intern() heißt es:

Code: Select all

It follows that for any two strings s and t, s.intern() == t.intern() is true if and only if s.equals(t) is true.
Aufgrund der Transitivität von equal() sind die beiden b-Strings gleich, sodass sie laut Dokumentation identisch sind. Der Aufruf von System.identityHashCode(b) sollte daher denselben Wert zurückgeben. Und das passiert manchmal, aber nur, wenn performComputation() in der Mitte nicht zu viel Arbeit leistet. Wenn es zu hart arbeitet – und ich vermute, dass es mit der Überlastung des Heaps zu tun hat – dann gibt System.identityHashCode(b) beim zweiten Mal einen anderen Wert zurück ... was unmöglich sein sollte, wenn das Dokumentation ist korrekt.
Dies ist der Code für performComputation:

Code: Select all

private static final Random random = new Random();

private static String randomString() {
StringBuilder builder = new StringBuilder();
for (int i = 0; i < 10000000; i++) {
builder.append((char)(random.nextInt(127 - 32) + 32));
}
return builder.toString();
}

private static void performComputation() {
for (int i = 0; i < 10; i++) {
String s = randomString();
System.out.println(s.substring(0, 3) + "..." + s.substring(s.length() - 3));
}
}
Wenn ich die Schleife von 10000000 Iterationen auf 10 ändere, erhalte ich denselben Identitäts-Hash.
Was genau ist hier los?
Bearbeiten: Vollständiger Code zum Reproduzieren des Verhaltens:

Code: Select all

import java.util.Random;

public class Main {

private static final Random random = new Random();

private static String randomString() {
StringBuilder builder = new StringBuilder();
for (int i = 0; i < 10000000; i++) {
builder.append((char)(random.nextInt(127 - 32) + 32));
}
return builder.toString();
}

private static void performComputation() {
for (int i = 0; i < 10; i++) {
String s = randomString();
System.out.println(s.substring(0, 3) + "..." + s.substring(s.length() - 3));
}
}

// ----------------------------------------------------------------------------------------------------------------

private static String buildSampleString() {
StringBuilder builder = new StringBuilder();
for (int i = 0; i < 10; i++) {
builder.append((char)(i + 'a'));
}
return builder.toString();
}

private static void performTest(String a) {
String b = buildSampleString().intern();
System.out.println("a vs. b: " + (a == b) + ", " + a.equals(b));
System.out.println(b + ": " + System.identityHashCode(b));
}

public static void main(String[] args) {
String a = buildSampleString();
performTest(a);
performComputation();
performTest(a);
}
}

Quick Reply

Change Text Case: 
   
  • Similar Topics
    Replies
    Views
    Last post