根据String#intern(),如果在String池中找到String,则 intern
方法应该从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
将不会被打印 . 但结果是:两行都打印出来 . 这意味着,默认情况下,字符串常量被实现 . 但如果是这样,那为什么我们需要 intern
方法呢?换句话说,我们什么时候应该使用这种方法?
15 回答
默认情况下,字符串文字和常量是固定的 . 也就是说,
"foo" == "foo"
(由字符串文字声明),但new String("foo") != new String("foo")
.当两个字符串独立创建时,
intern()
允许您比较它们,如果之前不存在引用,它还可以帮助您在字符串池中创建引用 .当您使用
String s = new String(hi)
时,java会创建一个新的字符串实例,但是当您使用String s = "hi"
时,java会检查代码中是否存在单词"hi"的实例,如果它存在,则只返回引用 .由于比较字符串是基于引用,
intern()
有助于您创建引用并允许您比较字符串的内容 .在代码中使用
intern()
时,它会清除引用同一对象的字符串所使用的空间,并仅返回内存中已存在的相同对象的引用 .但是在使用p5的情况下:
仅复制p3的内容并新创建p5 . 所以它不是实习生 .
所以输出将是:
为什么不能在需要使用实习生的地方使用字符串文字?默认情况下,字符串文字用法将重用现有的字符串文字 . 那么为什么我们需要创建新的String(“something”.intern()而不是仅仅分配“某些东西”?
OUTPUT
你应该计算两个周期时间,即编译时间和运行时间 . 例如:
一方面,在示例1中,我们发现结果都返回true,因为在编译时,jvm会将“test”放到文字字符串池中,如果jvm找到“test”存在,那么它将使用exists one,在例1中,“test”字符串都指向相同的内存地址,因此示例1将返回true . 另一方面,在例2中,substring()的方法在运行时执行,在“test”==“!test”.substring(1)的情况下,池将创建两个字符串对象,“测试“and”!test“,所以它们是不同的引用对象,所以这种情况将返回false,在”test“==”!test“.substring(1).intern()的情况下,实习生的方法( )将把“”!test“.substring(1)”放到文字字符串池中,所以在这种情况下,它们是相同的引用对象,因此将返回true .
string intern()方法用于在字符串常量池中创建堆字符串对象的精确副本 . 字符串常量池中的字符串对象会自动实现,但堆中的字符串对象则不会 . 创建实习生的主要用途是节省内存空间并更快地比较字符串对象 .
资料来源:What is string intern in java?
学习Java String实习生 - 一劳永逸
java中的字符串是设计中的不可变对象 . 因此,默认情况下,两个具有相同值的字符串对象将是不同的对象 . 但是,如果我们希望节省内存,我们可以通过一个名为string intern的概念来指示使用相同的内存 .
The below rules would help you understand the concept in clear terms:
String类维护一个最初为空的intern-pool . 此池必须保证包含仅具有唯一值的字符串对象 .
具有相同值的所有字符串文字必须被视为相同的内存位置对象,因为它们没有区别的概念 . 因此,具有相同值的所有此类文字将在内部池中生成单个条目,并将引用相同的内存位置 .
两个或多个文字的连接也是文字 . (因此规则#2将适用于他们)
作为对象创建的每个字符串(即除了文字之外的任何其他方法)将具有不同的内存位置,并且不会在内部池中创建任何条目
文字与非文字的连接将使非文字 . 因此,结果对象将具有新的内存位置,并且不会在内部池中创建条目 .
在字符串对象上调用intern方法,或者创建一个进入内部池的新对象,或者从池中返回具有相同值的现有对象 . 对不在intern-pool中的任何对象的调用不会将对象移动到池中 . 它创建了另一个进入池的对象 .
Example:
注意:此处不讨论字符串实习生的动机案例 . 但是,节省内存肯定是其中之一主要目标 .
在最近的一个项目中,一些巨大的数据结构被设置了从数据库读入的数据(因此不是字符串常量/文字),但是有大量的重复 . 这是一个银行应用程序,像一个适度的集(可能是100或200)公司的名称出现在各地 . 数据结构已经很大,如果所有这些公司名称都是唯一的对象,那么它们就会溢出内存 . 相反,所有数据结构都引用了相同的100或200个String对象,从而节省了大量空间 .
实习字符串的另一个小优点是
==
可用于(成功!)比较字符串,如果所有涉及的字符串都保证被实现 . 除了更精简的语法之外,这也是性能增强 . 正如其他人所指出的那样,这样做会带来引入编程错误的巨大风险,所以这应该只是作为最后手段的绝对措施 .缺点是,实际上,String需要花费更多的时间而不是简单地将它放在堆上,并且可能会限制实习字符串的空间,具体取决于Java实现 . 当您处理已知合理数量的字符串并且有许多重复时,最好这样做 .
Java自动实习字符串文字 . 这意味着在许多情况下,==运算符似乎对字符串的工作方式与对int或其他原始值的处理方式相同 .
由于对于字符串文字自动实习,
intern()
方法将用于使用new String()
构造的字符串使用你的例子:
将返回:
有关更多信息,请参阅JavaTechniques "String Equality and Interning" .
Interned Strings避免重复字符串 . 实习以节省更多CPU时间来节省RAM,以检测和替换重复的字符串 . 每个字符串只有一个被复制的副本,无论有多少引用都指向它 .
虽然Java默认会自动插入所有字符串,但请记住,当它们不是常量时我们只需要实习字符串,并且我们希望能够快速将它们与其他字符串进行比较 . 应该对使用new String()构造的字符串使用intern()方法,以便通过==运算符进行比较 .
公共类TestString {
}
//输出
真正
假
假
假
真正
真正
真正
真正
真正
真正
http://en.wikipedia.org/wiki/String_interning
string interning是一种只存储每个不同字符串值的一个副本的方法,该值必须是不可变的 . 实习字符串使得一些字符串处理任务更加节省时间或空间,代价是在创建或实现字符串时需要更多时间 . 不同的值存储在字符串实习池中 .
我希望使用带有实习字符串的
==
加2美分 .String.equals
做的第一件事是this==object
.因此虽然有一些微不足道的性能提升(你不是在调用方法),但从维护者的角度来看,使用
==
是一场噩梦,因为一些实习字符串倾向于变成非实习 .所以我建议不要依赖
==
的特殊情况作为实习字符串,但总是使用equals
作为Gosling的意图 .编辑:实习成为非实习:
在版本2.0中,维护者决定公开
hasReferenceVal
,而没有详细说明它需要一个实体字符串数组 .现在您有一个可能很难找到的错误,因为在大多数情况下,数组包含文字值,有时使用非文字字符串 . 如果使用
equals
而不是==
那么hasReferenceVal
仍将继续工作 . 再一次,性能提升微乎其微,但维护成本很高 .如你所说,字符串
intern()
方法将首先从字符串池中找到,如果找到,则它将返回指向该字符串的对象,或者将新的字符串添加到池中 .s1
和s2
是指向字符串池"Hello"的两个对象,使用"Hello".intern()
将找到s1
和s2
. 所以"s1 == s3"
返回true,以及s3.intern()
.Interned Strings避免重复字符串 . 实习以节省更多CPU时间来节省RAM,以检测和替换重复的字符串 . 每个字符串只有一个被复制的副本,无论有多少引用都指向它 . 由于字符串是不可变的,如果两种不同的方法偶然使用相同的字符串,它们可以共享相同字符串的副本 . 将重复的字符串转换为共享字符串的过程称为interning.String.intern(),它为您提供规范主字符串的地址 . 您可以将实际的字符串与简单的==(比较指针)进行比较,而不是比较字符串逐个比较字符串的等号 . 因为字符串是不可变的,所以实习生进程可以自由地进一步节省空间,例如,当没有为"pot"创建单独的字符串文字时它作为"hippopotamus"等其他文字的子字符串存在 .
要查看更多http://mindprod.com/jgloss/interned.html