What is the output of following code and Why ?
public class TestString {
public static void main(String[] args) { String str1 = "Hello"; String str2 = new String("Hello"); System.out.println(str1.hashCode() == str2.hashCode()); }}
Output: true
Explanation:
Line 1: String str1 = "Hello";
Here String literal (object) is created in the String constant pool area of the heap memory. JVM see that it is string literal and there is no existing literal with that value in String constant pool, so it creates a new String literal with value "Hello" in the String constant pool. This is done by JVM for efficient usage of memory. The reference variable str1 refers(read have address of this String literal) to this String literal.
Line 2: String str2 = new String("Hello");
Here as we are creating String object using new operator, JVM creates a new String object in heap with value "Hello". str2 refers to(or read have address of this newly created object in heap) to object in heap.
Line 3: System.out.println(str1.hashCode() == str2.hashCode());
Here we are calling hashCode() method on str1 and str2 and comparing hashcodes of objects referred by str1 and str2 respectively.
Now because String class has overriden the hashCode() method of Object class from which it inherits and the overriden implementation in the String class calculates hashCode based on the value of String, hashCode of both the String objects will be same as both have same value.
Here is source code of hashCode() method from String class (JDK 17) and you can see that hashCode is calculated on the basis of value.
/**
* Returns a hash code for this string. The hash code for a
* {@code String} object is computed as
* <blockquote><pre>
* s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
* </pre></blockquote>
* using {@code int} arithmetic, where {@code s[i]} is the
* <i>i</i>th character of the string, {@code n} is the length of
* the string, and {@code ^} indicates exponentiation.
* (The hash value of the empty string is zero.)
*
* @return a hash code value for this object.
*/
public int hashCode() {
// The hash or hashIsZero fields are subject to a benign data race,
// making it crucial to ensure that any observable result of the
// calculation in this method stays correct under any possible read of
// these fields. Necessary restrictions to allow this to be correct
// without explicit memory fences or similar concurrency primitives is
// that we can ever only write to one of these two fields for a given
// String instance, and that the computation is idempotent and derived
// from immutable state
int h = hash;
if (h == 0 && !hashIsZero) {
h = isLatin1() ? StringLatin1.hashCode(value)
: StringUTF16.hashCode(value);
if (h == 0) {
hashIsZero = true;
} else {
hash = h;
}
}
return h;
}