When should we use intern method of String on String literals

后端 未结 14 790
生来不讨喜
生来不讨喜 2020-11-22 08:11

According to String#intern(), intern method is supposed to return the String from the String pool if the String is found in String pool, otherwise a new string

相关标签:
14条回答
  • 2020-11-22 08:31
        public static void main(String[] args) {
        // TODO Auto-generated method stub
        String s1 = "test";
        String s2 = new String("test");
        System.out.println(s1==s2);              //false
        System.out.println(s1==s2.intern());    //true --> because this time compiler is checking from string constant pool.
    }
    
    0 讨论(0)
  • 2020-11-22 08:38

    Learn Java String Intern - once for all

    Strings in java are immutable objects by design. Therefore, two string objects even with same value will be different objects by default. However, if we wish to save memory, we could indicate to use same memory by a concept called string intern.

    The below rules would help you understand the concept in clear terms:

    1. String class maintains an intern-pool which is initially empty. This pool must guarantee to contain string objects with only unique values.
    2. All string literals having same value must be considered same memory-location object because they have otherwise no notion of distinction. Therefore, all such literals with same value will make a single entry in the intern-pool and will refer to same memory location.
    3. Concatenation of two or more literals is also a literal. (Therefore rule #2 will be applicable for them)
    4. Each string created as object (i.e. by any other method except as literal) will have different memory locations and will not make any entry in the intern-pool
    5. Concatenation of literals with non-literals will make a non-literal. Thus, the resultant object will have a new memory location and will NOT make an entry in the intern-pool.
    6. Invoking intern method on a string object, either creates a new object that enters the intern-pool or return an existing object from the pool that has same value. The invocation on any object which is not in the intern-pool, does NOT move the object to the pool. It rather creates another object that enters the pool.

    Example:

    String s1=new String (“abc”);
    String s2=new String (“abc”);
    If (s1==s2)  //would return false  by rule #4
    If (“abc” == “a”+”bc” )  //would return true by rules #2 and #3
    If (“abc” == s1 )  //would return false  by rules #1,2 and #4
    If (“abc” == s1.intern() )  //would return true  by rules #1,2,4 and #6
    If ( s1 == s2.intern() )      //wound return false by rules #1,4, and #6
    

    Note: The motivational cases for string intern are not discussed here. However, saving of memory will definitely be one of the primary objectives.

    0 讨论(0)
  • 2020-11-22 08:42

    String literals and constants are interned by default. That is, "foo" == "foo" (declared by the String literals), but new String("foo") != new String("foo").

    0 讨论(0)
  • 2020-11-22 08:43

    I want to add my 2 cents on using == with interned strings.

    The first thing String.equals does is this==object.

    So although there is some miniscule performance gain ( you are not calling a method), from the maintainer point of view using == is a nightmare, because some interned strings have a tendency to become non-interned.

    So I suggest not to rely on special case of == for interned strings, but always use equals as Gosling intended.

    EDIT: interned becoming non-interned:

    V1.0
    public class MyClass
    {
      private String reference_val;
    
      ...
    
      private boolean hasReferenceVal ( final String[] strings )
      {
        for ( String s : strings )
        {
          if ( s == reference_val )
          {
            return true;
          }
        }
    
        return false;
      }
    
      private void makeCall ( )
      {
         final String[] interned_strings =  { ... init with interned values ... };
    
         if ( hasReference( interned_strings ) )
         {
            ...
         }
      }
    }
    

    In version 2.0 maintainer decided to make hasReferenceVal public, without going into much detail that it expects an array of interned strings.

    V2.0
    public class MyClass
    {
      private String reference_val;
    
      ...
    
      public boolean hasReferenceVal ( final String[] strings )
      {
        for ( String s : strings )
        {
          if ( s == reference_val )
          {
            return true;
          }
        }
    
        return false;
      }
    
      private void makeCall ( )
      {
         final String[] interned_strings =  { ... init with interned values ... };
    
         if ( hasReference( interned_strings ) )
         {
            ...
         }
      }
    }
    

    Now you have a bug, that may be very hard to find, because in majority of cases array contains literal values, and sometimes a non-literal string is used. If equals were used instead of == then hasReferenceVal would have still continue to work. Once again, performance gain is miniscule, but maintenance cost is high.

    0 讨论(0)
  • 2020-11-22 08:43

    http://en.wikipedia.org/wiki/String_interning

    string interning is a method of storing only one copy of each distinct string value, which must be immutable. Interning strings makes some string processing tasks more time- or space-efficient at the cost of requiring more time when the string is created or interned. The distinct values are stored in a string intern pool.

    0 讨论(0)
  • 2020-11-22 08:46

    you should make out two period time which are compile time and runtime time.for example:

    //example 1 
    "test" == "test" // --> true 
    "test" == "te" + "st" // --> true
    
    //example 2 
    "test" == "!test".substring(1) // --> false
    "test" == "!test".substring(1).intern() // --> true
    

    in the one hand,in the example 1,we find the results are all return true,because in the compile time,the jvm will put the "test" to the pool of literal strings,if the jvm find "test" exists,then it will use the exists one,in example 1,the "test" strings are all point to the same memory address,so the example 1 will return true. in the other hand,in the example 2,the method of substring() execute in the runtime time, in the case of "test" == "!test".substring(1),the pool will create two string object,"test" and "!test",so they are different reference objects,so this case will return false,in the case of "test" == "!test".substring(1).intern(),the method of intern() will put the ""!test".substring(1)" to the pool of literal strings,so in this case,they are same reference objects,so will return true.

    0 讨论(0)
提交回复
热议问题