什么时候应该使用string文字的实习方法

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

所以我试过这个:

 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. } 

我期待着s1 and s3 are same因为s3是被打印的,而s1 and s2 are same不会被打印出来。 但结果是:两行都打印出来。 这意味着,默认情况下,string常量是被禁用的。 但如果是这样的话,为什么我们需要intern方法呢? 换句话说,我们应该什么时候使用这种方法?

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

由于interning对于string是自动的,所以intern()方法将用在用new String()构造的new String()

用你的例子:

 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. } 

将返回:

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

有关更多信息,请参阅JavaTechniques“string平等和实习” 。

在最近的一个项目中,一些庞大的数据结构是由从数据库读入的数据(因此不是string常量/字面量)设置的,而且数据量巨大。 这是一个银行业务的应用程序,像一个微薄的集合(也许100或200)公司名称的东西出现在各地。 数据结构已经很大了,如果所有这些corp名称都是唯一的对象,它们就会溢出内存。 相反,所有的数据结构都引用了相同的100或200个String对象,从而节省了大量的空间。

internedstring的另一个小优点是, ==可以用来(成功!)比较string,如果所有涉及的string都被保证被执行。 除了更简洁的语法,这也是一个性能提升。 正如其他人所指出的那样,这样做存在引入编程错误的巨大风险,所以这只能作为绝望的措施来进行。

缺点是实习一个string需要更多的时间,而不是简单地把它扔在堆上,并且实施string的空间可能是有限的,这取决于Java的实现。 当处理已知的合理数量的string并且有很多重复时,最好做好。

我想添加我的2美分使用==与internedstring。

String.equals所做的第一件事就是this==object

所以,虽然有一些微不足道的性能增益(你没有调用方法),但从维护者的angular度来看,使用==是一个噩梦,因为一些被干扰的string有一个非实现的倾向。

所以我build议不要依靠==特殊情况来实现string,但总是使用equals作为Gosling的意图。

编辑:实习成为非实习生:

 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 ) ) { ... } } } 

在版本2.0维护者决定公开hasReferenceVal ,没有进入很多细节,它期望一个hasReferenceValstring数组。

 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 ) ) { ... } } } 

现在你有一个bug,可能很难find,因为在大多数情况下,数组包含字面值,有时使用非文字string。 如果使用equals而不是==那么hasReferenceVal将继续工作。 性能增益再次微乎其微,但维护成本高。

string文字和常量是默认实现的。 也就是说, "foo" == "foo" (由string文字声明),但是new String("foo") != new String("foo")

您应该编制两个句点时间,即编译时间和运行时间。例如:

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

一方面,在示例1中,我们发现结果全部返回true,因为在编译时,jvm会将“testing”放到string池中,如果jvmfind“test”存在,那么它将使用存在的一个,在示例1中,“testing”string都指向相同的存储器地址,因此示例1将返回true。 另一方面,在示例2中,substring()方法在运行时执行,在“test”==“!test”.substring(1)的情况下,池将创build两个string对象“ test“和”!test“,所以它们是不同的引用对象,所以在”test“==”!test“.substring(1).intern()的情况下,这种情况会返回false, )会将“!!test”.substring(1)“放到string池中,所以在这种情况下,它们是相同的引用对象,所以会返回true。

Internedstring避免重复的string。 为了检测和replace重复的string,Interning节省了RAM的CPU时间。 每个string只有一个被执行的副本,不pipe有多less个引用指向它。 由于string是不可变的,如果两个不同的方法偶然使用相同的string,他们可以共享同一个string的副本。 将重复的string转换为共享string的过程称为interning.String.intern()为您提供了规范的主string的地址。 你可以比较internedstring与简单的==(它比较指针),而不是比较string的字符一个接一个的等于 。 由于string是不可变的,因此实习过程可以进一步节省空间,例如,当它作为“hippopotamus”等其他字面量的子string存在时,不为“pot”创build单独的string文字。

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

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

stringinterning是一种只存储每个不同string值的一个副本的方法,它必须是不可变的。 实习中的string使一些string处理任务的时间或空间效率更高,但需要更多的时间来创build或实施string。 不同的值存储在string实习生池中。

 String p1 = "example"; String p2 = "example"; String p3 = "example".intern(); String p4 = p2.intern(); String p5 = new String(p3); String p6 = new String("example"); String p7 = p6.intern(); if (p1 == p2) System.out.println("p1 and p2 are the same"); if (p1 == p3) System.out.println("p1 and p3 are the same"); if (p1 == p4) System.out.println("p1 and p4 are the same"); if (p1 == p5) System.out.println("p1 and p5 are the same"); if (p1 == p6) System.out.println("p1 and p6 are the same"); if (p1 == p6.intern()) System.out.println("p1 and p6 are the same when intern is used"); if (p1 == p7) System.out.println("p1 and p7 are the same"); 

当两个string独立创build时, intern()允许您比较它们,并且如果之前不存在引用,则可以帮助您在string池中创build引用。

当您使用String s = new String(hi) ,java会创build一个新的string实例,但是当您使用String s = "hi" ,java会检查代码中是否存在单词“hi”的实例,如果存在,它只是返回参考。

由于比较string是基于引用的,因此intern()可以帮助你创build一个引用,并允许你比较string的内容。

在代码中使用intern()时,会清除引用同一对象的string使用的空间,并仅返回内存中已有的同一对象的引用。

但是在使用p5的情况下:

 String p5 = new String(p3); 

只有p3的内容被复制,并且新创build了p5。 所以它没有被实习

所以输出将是:

 p1 and p2 are the same p1 and p3 are the same p1 and p4 are the same p1 and p6 are the same when intern is used p1 and p7 are the same 

为什么不能在要求实习生使用的地方使用string? string字面量的默认使用将重用现有的string文字。 那么为什么我们需要创build新的String(“something).intern()而不是只分配”something“呢?

 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 

string intern()方法用于在string常量池中创build堆string对象的精确副本。 string常量池中的string对象是自动实现的,但堆中的string对象不是。 创build实习生的主要用途是节省内存空间并更快地比较string对象。

来源: 什么是在java中的string实习生?

正如你所说的那样,string intern()方法将首先从string池中find,如果find的话,它会返回指向该对象的对象,或者将一个新的string添加到池中。

  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 

s1s2是指向string池“Hello”的两个对象,使用"Hello".intern()将finds1s2 。 所以"s1 == s3"返回true,以及s3.intern()

学习Java String Intern – 一劳永逸

在Java中的string是不可变的对象的devise。 因此,即使具有相同值的两个string对象默认情况下也是不同的对象。 但是,如果我们希望节省内存,我们可以通过一个名为string intern的概念来指示使用相同的内存。

下面的规则将帮助你清楚地理解这个概念:

  1. String类维护一个最初为空的intern-pool。 该池必须保证只包含唯一值的string对象。
  2. 所有具有相同值的string文字必须被认为是相同的存储位置对象,因为它们没有区别的概念。 因此,所有这些具有相同值的文字都会在intern-pool中创build一个条目,并指向相同的内存位置。
  3. 两个或更多文字的连接也是一个文字。 (因此,规则2将适用于他们)
  4. 作为对象创build的每个string(即通过除文字以外的任何其他方法)将具有不同的内存位置,并且不会在内部池中进行任何input
  5. 文字与非文字的连接将成为非文字。 因此,生成的对象将有一个新的内存位置,不会在内部池中进行input。
  6. 在string对象上调用intern方法,可以创build一个新的对象,该对象进入intern-pool或从具有相同值的池中返回一个现有的对象。 对不在intern-pool的任何对象的调用不会将对象移动到池中。 而是创build另一个进入池的对象。

例:

 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 

注:string实习生的激励案例不在这里讨论。 但是,内存的节省肯定是主要的目标之一。