I think it has to to with the substring implementation prior to JDK 7.
At the time, the underlying character array size was not necessarily the string size. There were two fields, offset
& count
(i
an j
respectively) that were showing where is this
string in the underlying array, so the method was :
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = count;
if (n == anotherString.count) {
char v1[] = value;
char v2[] = anotherString.value;
int i = offset;
int j = anotherString.offset;
while (n-- != 0) {
if (v1[i++] != v2[j++])
return false;
}
return true;
}
}
return false;
}
After the change mentioned above, this method had to be also changed, so they just fixed n to be now the array length:
int n = value.length;
and got rid of j
(because there's no offset anymore):
int i = 0;
Now because i
has to be incremented after 2 usages, it is incremented in a separate statement :
if (v1[i] != v2[i])
return false;
i++;
I think that's it, there's a more concise implementation which is evident if it's to write it from scratch but given that it was a change pushed by another change ... Oracle people are ordinary people just like us :)
Benchmarking
As for benchmarking String#equals
vs Arrays#equals(char[], char[]
) I think we have to compare apples with apples, so I've put the two approaches for comparing 2 character arrays together :
public static void main(String[] args) {
final Random random = new Random();
final int arrays = 10000;
final int chars = 1000;
// generate the arrays
char[][] array = new char[arrays][chars];
for (int i = 0; i < arrays; i++) {
for (int j = 0; j < chars; j++) {
array[i][j] = (char)(random.nextInt(94) + 33);
}
}
// compare using Arrays equals
long before = System.nanoTime();
for (int i = 0; i < arrays; i++) {
for (int j = 0; j < chars; j++) {
equals_Arrays(array[i], array[j]);
}
}
System.out.println(System.nanoTime() - before);
// compare using String equals
before = System.nanoTime();
for (int i = 0; i < arrays; i++) {
for (int j = 0; j < chars; j++) {
equals_String(array[i], array[j]);
}
}
System.out.println(System.nanoTime() - before);
}
private static boolean equals_Arrays(char[] a, char[] a2) {
if (a == a2)
return true;
if (a == null || a2 == null)
return false;
int length = a.length;
if (a2.length != length)
return false;
for (int i = 0; i < length; i++)
if (a[i] != a2[i])
return false;
return true;
}
private static boolean equals_String(char[] v1, char[] v2) {
if (v1 == v2)
return true;
if (v1 == null || v2 == null)
return false;
int length = v1.length;
if (length == v2.length) {
int i = 0;
while (length-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
return false;
}
On my box I see no notable difference.