Java 我们什么时候应该在字符串文字上使用字符串的实习生方法

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1855170/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 23:18:53  来源:igfitidea点击:

When should we use intern method of String on String literals

javastringstring-interning

提问by Rakesh Juyal

According to String#intern(), internmethod is supposed to return the String from the String pool if the String is found in String pool, otherwise a new string object will be added in String pool and the reference of this String is returned.

根据String#intern()intern如果在字符串池中找到字符串,方法应该从字符串池返回字符串,否则将在字符串池中添加一个新的字符串对象并返回该字符串的引用。

So i tried this:

所以我试过这个:

String s1 = "Rakesh";
String s2 = "Rakesh";
String s3 = "Rakesh".intern();

if ( s1 == s2 ){
    System.out.println("s1 and s2 are same");  // 1.
}

if ( s1 == s3 ){
    System.out.println("s1 and s3 are same" );  // 2.
}

I was expecting that s1 and s3 are samewill be printed as s3 is interned, and s1 and s2 are samewill not be printed. But the result is: both lines are printed. So that means, by default String constants are interned. But if it is so, then why do we need the internmethod? In other words when should we use this method?

我原以为s1 and s3 are same将在 s3 实习时打印,并且s1 and s2 are same不会打印。但结果是:两行都被打印出来。所以这意味着,默认情况下字符串常量是实习的。但如果是这样,那我们为什么需要这个intern方法呢?换句话说,我们什么时候应该使用这种方法?

采纳答案by Filipe Miguel Fonseca

Java automatically interns String literals. This means that in many cases, the == operator appears to work for Strings in the same way that it does for ints or other primitive values.

Java 自动实习字符串文字。这意味着在许多情况下,== 运算符似乎对字符串的工作方式与对整数或其他原始值的工作方式相同。

Since interning is automatic for String literals, the intern()method is to be used on Strings constructed with new String()

由于字符串文字的实习是自动的,因此该intern()方法将用于用new String()

Using your example:

使用您的示例:

String s1 = "Rakesh";
String s2 = "Rakesh";
String s3 = "Rakesh".intern();
String s4 = new String("Rakesh");
String s5 = new String("Rakesh").intern();

if ( s1 == s2 ){
    System.out.println("s1 and s2 are same");  // 1.
}

if ( s1 == s3 ){
    System.out.println("s1 and s3 are same" );  // 2.
}

if ( s1 == s4 ){
    System.out.println("s1 and s4 are same" );  // 3.
}

if ( s1 == s5 ){
    System.out.println("s1 and s5 are same" );  // 4.
}

will return:

将返回:

s1 and s2 are same
s1 and s3 are same
s1 and s5 are same

In all the cases besides of s4variable, a value for which was explicitly created using newoperator and where internmethod was not used on it's result, it is a single immutable instance that's being returned JVM's string constant pool.

s4变量之外的所有情况下,使用new运算符显式创建的值以及intern未对其结果使用方法的情况下,它是单个不可变实例,返回JVM 的字符串常量池

Refer to JavaTechniques "String Equality and Interning"for more information.

有关更多信息,请参阅JavaTechniques“字符串相等和实习”

回答by Bozho

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

默认情况下,字符串文字和常量是内部的。也就是说,"foo" == "foo"(由字符串文字声明),但是new String("foo") != new String("foo").

回答by Carl Smotricz

On a recent project, some huge data structures were set up with data that was read in from a database (and hence not String constants/literals) but with a huge amount of duplication. It was a banking application, and things like the names of a modest set (maybe 100 or 200) corporations appeared all over the place. The data structures were already large, and if all those corp names had been unique objects they would have overflowed memory. Instead, all the data structures had references to the same 100 or 200 String objects, thus saving lots of space.

在最近的一个项目中,一些巨大的数据结构被设置为使用从数据库读取的数据(因此不是字符串常量/文字),但具有大量重复。这是一个银行应用程序,到处都出现了一些小公司(可能是 100 或 200 家)公司的名称。数据结构已经很大了,如果所有这些公司名称都是唯一的对象,它们就会溢出内存。相反,所有数据结构都引用了相同的 100 或 200 个 String 对象,从而节省了大量空间。

Another small advantage of interned Strings is that ==can be used (successfully!) to compare Strings if all involved strings are guaranteed to be interned. Apart from the leaner syntax, this is also a performance enhancement. Butas others have pointed out, doing this harbors a great risk of introducing programming errors, so this should be done only as a desparate measure of last resort.

实习字符串的另一个小优点是,==如果保证所有涉及的字符串都被实习,则可以使用(成功!)比较字符串。除了更精简的语法之外,这也是一种性能增强。正如其他人所指出的那样,这样做会带来很大的引入编程错误的风险,所以这应该只作为最后手段的绝望措施。

The downside is that interning a String takes more time than simply throwing it on the heap, and that the space for interned Strings may be limited, depending on the Java implementation. It's best done when you're dealing with a known reasonable number of Strings with many duplications.

缺点是,实习字符串比简单地将其扔到堆上需要更多时间,而且实习字符串的空间可能有限,具体取决于 Java 实现。当您处理具有许多重复的已知合理数量的字符串时,最好这样做。

回答by Alexander Pogrebnyak

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

我想在使用==实习字符串时增加我的 2 美分。

The first thing String.equalsdoes is this==object.

做的第一件事String.equalsthis==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 equalsas Gosling intended.

所以我建议不要依赖于特殊情况的==intern 字符串,而是始终equals按照 Gosling 的意图使用。

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 hasReferenceValpublic, without going into much detail that it expects an array of interned strings.

在 2.0 版本中,维护者决定hasReferenceVal公开,但没有详细说明它需要一个内部字符串数组。

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 equalswere used instead of ==then hasReferenceValwould have still continue to work. Once again, performance gain is miniscule, but maintenance cost is high.

现在您有一个错误,可能很难找到,因为在大多数情况下数组包含文字值,有时使用非文字字符串。如果equals被使用而不是==那么hasReferenceVal将仍然继续工作。再一次,性能提升微乎其微,但维护成本却很高。

回答by inter18099

Interned Strings avoid duplicate Strings. Interning saves RAM at the expense of more CPU time to detect and replace duplicate Strings. There is only one copy of each String that has been interned, no matter how many references point to it. Since Strings are immutable, if two different methods incidentally use the same String, they can share a copy of the same String. The process of converting duplicated Strings to shared ones is called interning.String.intern()gives you the address of the canonical master String. You can compare interned Strings with simple == (which compares pointers) instead of equalswhich compares the characters of the String one by one. Because Strings are immutable, the intern process is free to further save space, for example, by not creating a separate String literal for "pot" when it exists as a substring of some other literal such as "hippopotamus".

实习字符串避免重复的字符串。实习节省了 RAM,但会花费更多的 CPU 时间来检测和替换重复的字符串。无论有多少引用指向它,每个字符串都只有一个副本。由于字符串是不可变的,如果两个不同的方法偶然使用同一个字符串,它们可以共享同一个字符串的副本。将重复字符串转换为共享字符串的过程称为interning.String.intern()为您提供规范主字符串的地址。您可以使用简单的 ==(比较指针)而不是equals来比较实习字符串它将字符串的字符一一比较。因为字符串是不可变的,所以实习生进程可以自由地进一步节省空间,例如,当“pot”作为某些其他文字(例如“hippopotamus”)的子字符串存在时,不会为“pot”创建单独的字符串文字。

To see more http://mindprod.com/jgloss/interned.html

要查看更多http://mindprod.com/jgloss/interned.html

回答by bbcbcgb

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

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.

字符串实习是一种只存储每个不同字符串值的一个副本的方法,它必须是不可变的。驻留字符串使一些字符串处理任务在时间或空间上更加高效,代价是在创建或驻留字符串时需要更多时间。不同的值存储在字符串实习生池中。

回答by anish

String s1 = "Anish";
        String s2 = "Anish";

        String s3 = new String("Anish");

        /*
         * When the intern method is invoked, if the pool already contains a
         * string equal to this String object as determined by the
         * 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.
         */
        String s4 = new String("Anish").intern();
        if (s1 == s2) {
            System.out.println("s1 and s2 are same");
        }

        if (s1 == s3) {
            System.out.println("s1 and s3 are same");
        }

        if (s1 == s4) {
            System.out.println("s1 and s4 are same");
        }

OUTPUT

输出

s1 and s2 are same
s1 and s4 are same

回答by thinkinjava

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.

一方面,在示例1中,我们发现结果都返回true,因为在编译时,jvm会将“test”放入字符串池中,如果jvm find“test”存在,则它将使用存在的,在示例 1 中,“测试”字符串都指向相同的内存地址,因此示例 1 将返回 true。另一方面,在示例2中,substring()的方法在运行时执行,在"test" == "!test".substring(1)的情况下,池将创建两个字符串对象," test"和"!test",所以它们是不同的引用对象,所以这种情况会返回false,在"test" == "!test".substring(1).intern()的情况下,intern()的方法) 会将 ""!test".substring(1)" 放入文字字符串池中,

回答by user2485429

string intern() method is used to create an exact copy of heap string object in string constant pool. The string objects in the string constant pool are automatically interned but string objects in heap are not. The main use of creating interns is to save the memory space and to perform faster comparison of string objects.

string intern() 方法用于在字符串常量池中创建堆字符串对象的精确副本。字符串常量池中的字符串对象会自动驻留,但堆中的字符串对象不会。创建实习生的主要用途是节省内存空间和更快地进行字符串对象的比较。

Source : What is string intern in java?

来源:java 中的字符串实习生是什么?

回答by WendellWu

As you said, that string intern()method will first find from the String pool, if it finds, then it will return the object that points to that, or will add a new String into the pool.

如您所说,该字符串intern()方法将首先从字符串池中查找,如果找到,则返回指向该对象的对象,或者将新的字符串添加到池中。

    String s1 = "Hello";
    String s2 = "Hello";
    String s3 = "Hello".intern();
    String s4 = new String("Hello");

    System.out.println(s1 == s2);//true
    System.out.println(s1 == s3);//true
    System.out.println(s1 == s4.intern());//true

The s1and s2are two objects pointing to the String pool "Hello", and using "Hello".intern()will find that s1and s2. So "s1 == s3"returns true, as well as to the s3.intern().

s1s2是指向字符串池“你好”,并使用两个物体"Hello".intern()会发现,s1s2。因此"s1 == s3"返回 true,以及s3.intern().