In depth understanding of two ways of creating objects by String

Posted by twigletmac on Tue, 01 Feb 2022 12:59:45 +0100

Introduction: as we all know, there are two ways to create string objects:
String name1 = "jack";
String name2 = new String("jack");

1. String name1 = “jack”; Interpretation of

  • "jack" is a string constant, also known as a string literal, which is located in the string constant pool
  • name1 is a stack variable that points to the String object in the constant pool
  • If the literal already exists in the constant pool, return the literal address in the constant pool to name1
  • If there is no literal in the pool, create the literal in the pool and return the address to name1
  • jdk1.7 and later, the constant pool is moved from the method area to the heap

2. String name2 = new String(“jack”); Interpretation of

  • The first step is to create a literal "jack", which is also a process of creating an object. It will follow the steps in 1, that is, it will find out whether there is a literal "jack" from the constant pool, and the result is found.
  • Take the literal "jack" as a String parameter, call the corresponding constructor, and create a String object for the second time
 public String(String original) {
        this.value = original.value;
        this.hash = original.hash;
    }
  • That is to say, although the new String object is outside the constant pool, the field value [] it maintains is the same character array as the value [] of the "jack" object in the constant pool, which further saves space.
  • In other words, this second method of creating a String object will actually create a String object twice, but as the literal quantity of the transition, if there is no reference to it, it will soon be recycled by GC. In this case, because name1 points to this literal in the pool, it will not be recycled by GC
  • How to prove that they point to the same character array? (the output content in the code will be noted later)
	String s1 = "You're a fool!";
	String s2 = new String("You're a fool!");
	//At this time, just get the value [] of two strings, and then compare the unique ID to know whether it is the same character array!
	//The problem is that value is private and can only be reflected
	Field valueStringField = String.class.getDeclaredField("value");
	valueStringField.setAccessible(true);//Opening authority
	char[] value1 = (char[])valueStringField.get(s1);
	char[] value2 = (char[])valueStringField.get(s2);
	System.out.println(value1 == value2);//true
	System.out.println(System.identityHashCode(value1));//2133927002
	System.out.println(System.identityHashCode(value2));//2133927002
	//The two are exactly the same, indicating that it is a character array
  • What is system identityHashCode(obj)? Why not use obj hashCode()? The following answers:

3. hashCode()

  • The total contract of hashCode is:

    • If the same object calls hashCode multiple times, the values must be consistent, but they do not have to be consistent from one execution to another
    • Equals of two objects is true < = > the hashCode values of two objects are equal. This rule indicates that this rule must be implemented when overriding hashCode and equals methods
    • If two objects are different, there is no need to ensure that their hashCode values are different
    • In terms of sufficient and unnecessary mathematics, the necessary and sufficient conditions are as follows:
      Same object = > equal hashcode values
      obj1.equals(obj2) is true < = > the hashcode value is equal (the class needs to override the equals() method, and the UN overridden equals() is equivalent to = =)
      Different objects, but equals is true = > hashcode values are equal
  • String overrides hashCode() and equals() methods:

    public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
        if (anObject instanceof String) {
            String anotherString = (String)anObject;
            int n = value.length;
            if (n == anotherString.value.length) {
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;
                while (n-- != 0) {
                    if (v1[i] != v2[i])
                        return false;
                    i++;
                }
                return true;
            }
        }
        return false;
    }
    public int hashCode() {
        int h = hash;
        if (h == 0 && value.length > 0) {
            char val[] = value;

            for (int i = 0; i < value.length; i++) {
                h = 31 * h + val[i];
            }
            hash = h;
        }
        return h;
    }    
  • Therefore, the value of hahCode cannot be used to judge whether two objects are the same object, which leads to system identityHashCode(obj)

4. System.identityHashCode(obj)

  • This is the unique identification of the object. No matter whether the object rewrites the hashCode method or not, as long as the addresses of the two objects are different, the identityHashCode(obj) is different.

5. String.intern() method

  • How to put a new String object in the heap into the constant pool?
String string = new String("fool");
String poolString = string.intern();
  • This method will create a new String object in the constant pool, but value [] is the same as the object in the heap
  • First prove that they are different objects:
System.out.println(string == string.intern());//false
System.out.println(System.identityHashCode(string));//21685669
System.out.println(System.identityHashCode(string.intern()));//2133927002
  • Prove again that the value of the two is still the same: (the private domain can only be obtained through reflection)
	Field valueStringField = String.class.getDeclaredField("value");
	valueStringField.setAccessible(true);//Punch in channel
	char[] value1 = (char[]) valueStringField.get(string);
	char[] value2 = (char[]) valueStringField.get(string.intern());
	System.out.println(System.identityHashCode(value1));//325040804
	System.out.println(System.identityHashCode(value2));//325040804
  • This proves that the value [] field of two different String objects points to the same character array

Topics: Java string reflection hashcode