Home > OS >  The execution of the same code in the main method and JUnit is inconsistent
The execution of the same code in the main method and JUnit is inconsistent

Time:09-04

public static void main(String[] args) {
         String s1 = new String("1")   new String("1");
         s1.intern();
         String s2 = "11";
         System.out.println(s1 == s2); // This result is true.
    }
@Test
    public void test2(){
        String s1 = new String("1")   new String("1");
        s1.intern();
        String s2 = "11";
        System.out.println(s1 == s2); // This result is false.
    }

1.Why is the execution result of my code in the main method different from that in the JUnit unit test

CodePudding user response:

Works on my machine for both junit 4 and 5.8.1 with java 18 when running the same code.
Can you give more info on your setup? Eg. junit version/java version etc.
Do other methods from junit work fine? Eg. assertEquals

import org.junit.jupiter.api.Test;

public class Main{
        public static void main(String[] args) {
                String s1 = new String("1")   new String("1");
                s1.intern();
                String s2 = "11";
                System.out.println(s1 == s2); // This result is true.
        }
        @Test
        public void test2(){
                String s1 = new String("1")   new String("1");
                s1.intern();
                String s2 = "11";
                System.out.println(s1 == s2); // This result is false.
        }

        }

CodePudding user response:

Since the returned instance of intern() is being ignored, the code will behave differently depending if the "11" string was already interned or not.

See the documentation of the intern() method:

When the intern method is invoked, if the pool already contains a string equal to this String object as determined by the equals(Object) method, then the string from the pool is returned. Otherwise, this String object is added to the pool and a reference to this String object is returned.

In other words, calling s1.intern() when the string is not yet interned, would return the same instance, that is, the instance of s1 will be the interned instance and so s1 == "11" results in true. Otherwise, if "11" was already added to the pool¹, s1.intern() will return the instance that is already in the pool and not changed the reference stored in s1; so s1 == "11" must return false.

The correct way to use the intern() method is to use the returned instance:

s1 = s1.intern();

This guarantees that s1 is always the instance from the string pool.


¹ A string will be added to the pool by any previous call of intern() on a string with he same content or anywhere, including any library or standard classes, the "11" literal is used.



Comparing what can happen if the string is or not already in the pool.
@100 means a pointer to an instance, the number (100) being a fictive ID (or address) of that instance.

"11" not yet in the pool:

String s1 = new String("1")   new String("1");  // s1=@100
// the literal "1" is in the pool, but the resulting "11" is a new instance, not in/from the pool

s1.intern();  // s1=@100; returns @100
// "11" is not in the pool, so the instance (@100) is added to the pool and returned

String s2 = "11";  // s2=@100
// since there is already a "11" (@100) in the pool, it is used for the literal

System.out.println(s1 == s2);  // true since @100 == @100

"11" // @100 already in the pool, maybe the literal was used before:

 // somewhere else, already executed (main, standard java classes, junit, ...)
var x = "11";
// or
System.out.println("11");
// now "11" is in the string pool

...

String s1 = new String("1")   new String("1");  // s1=@101
// the literal "1" is in the pool, but the resulting "11" is a new instance, not from the pool

s1.intern();  // s1=@101; returns @100 (the value from the pool)
// "11" is in the pool, so the instance (@101) is NOT added to the pool and the pool instance @100 returned
// s1 is not changed and still contains @101, since the return value was not assigned to it

String s2 = "11";  // s2=@100
// since there is already a "11" (@100) in the pool, it is used for the literal

System.out.println(s1 == s2);  // false since @101 == @100
  • Related