使用java.lang.String.intern()是否是一种良好的做法?
Javadoc没有给出太多细节。(简而言之:它返回字符串的规范表示形式,允许使用使用java.lang.String.intern()是否是一种良好的做法?,java,string,Java,String,Javadoc没有给出太多细节。(简而言之:它返回字符串的规范表示形式,允许使用==比较插入的字符串) 我什么时候会使用这个函数来支持String.equals() Javadoc中是否有未提及的副作用,即JIT编译器或多或少的优化 String.intern()还有其他用法吗 我什么时候会使用这个函数来表示String.equals() 当您需要速度时,因为您可以通过引用比较字符串(=比等于快) Javadoc中是否没有提到副作用 主要缺点是,您必须记住确保实际执行intern()所有要比
==
比较插入的字符串)
- 我什么时候会使用这个函数来支持
String.equals()
- Javadoc中是否有未提及的副作用,即JIT编译器或多或少的优化
还有其他用法吗String.intern()
(来自Michael Borgwardt)我不知道有什么好处,如果有好处的话,人们会认为equals()本身会在内部使用intern()(事实并非如此)
这(几乎)与字符串比较无关。用于在应用程序中有多个具有相同内容的字符串时节省内存。通过使用
String.intern()
应用程序从长远来看只有一个实例,其副作用是您可以执行快速引用相等比较,而不是普通的字符串比较(但这通常是不可取的,因为忘记只插入一个实例很容易中断).只有当相等比较成为字符串多重比较的瓶颈时,我才会检查intern和==-比较,而不是equals比较。这不太可能有助于进行少量比较,因为intern()不是免费的。在积极地插入字符串之后,您会发现对intern()的调用越来越慢
我什么时候会使用这个函数来表示String.equals()
考虑到他们做不同的事情,可能永远不会
出于性能原因而保留字符串,以便您可以比较它们的引用相等性,只有在您保留字符串引用一段时间的情况下才有好处-来自用户输入或IO的字符串不会被保留
这意味着在您的应用程序中,您接收来自外部源的输入,并将其处理成一个具有语义值(比如标识符)的对象,但该对象的类型与原始数据不可区分,并且对于程序员应该如何使用该对象有不同的规则
与使用引用语义重载java.lang.String
类型(如果该类型恰好是用户ID)相比,创建一个UserId
类型(可以轻松创建线程安全的通用内部机制)并充当一个打开的枚举,几乎总是比创建一个UserId
类型要好
这样,您就不会混淆某个特定字符串是否已被插入,并且可以在开放枚举中封装所需的任何其他行为。我认为它不值得维护 大多数情况下,没有必要,也没有性能优势,除非您的代码对子字符串做了大量工作。在这种情况下,String类将使用原始字符串加上偏移量来节省内存。如果您的代码大量使用子字符串,那么我怀疑这只会导致内存需求爆炸。
String.intern()
在现代JVM中肯定是垃圾收集的。由于GC活动,以下内容永远不会耗尽内存:
// java -cp . -Xmx128m UserOfIntern
public class UserOfIntern {
public static void main(String[] args) {
Random random = new Random();
System.out.println(random.nextLong());
while (true) {
String s = String.valueOf(random.nextLong());
s = s.intern();
}
}
}
更多信息请参见。使用intern的真正原因并非上述。 您可以在内存不足错误后使用它。典型程序中的许多字符串都是其他大字符串的string.substring()[请考虑从100K xml文件中删除用户名。 java实现是这样的,子字符串包含对原始字符串的引用以及该大字符串中的start+end(其背后的思想是重用同一个大字符串) 在1000个大文件之后,您只保存1000个短名称,您将在内存中保留全部1000个文件!
解决方案:在这个场景中,只需使用smallsubstring.intern()我使用intern来节省内存,我在内存中保存了大量字符串数据,并开始使用intern()节省了大量内存。不幸的是,尽管它使用的内存很少,但它使用的内存存储在PermGen内存中,而不是堆中,因此很难向客户解释如何增加此类内存的分配
那么,是否有替代intern()的方法来减少内存消耗,(==与equals的性能优势对我来说不是问题)比较字符串与==比使用equals()快得多。 5时间快,但由于字符串比较通常只代表应用程序总执行时间的一小部分,因此总体增益远小于此值,最终增益将稀释到几个百分点 String.intern()将字符串从堆中拉出并放入PermGen中 圣
Integer i = 1;
System.out.println("1".equals(i));
/**
* Extends the notion of String.intern() to different mechanisms and
* different types. For example, an implementation can use an
* LRUCache<T,?>, or a WeakHashMap.
*/
public interface Internalizer<T> {
public T get(T obj);
}
public static class LRUInternalizer<T> implements Internalizer<T> {
private final LRUCache<T, T> cache;
public LRUInternalizer(int size) {
cache = new LRUCache<T, T>(size) {
private static final long serialVersionUID = 1L;
@Override
protected T retrieve(T key) {
return key;
}
};
}
@Override
public T get(T obj) {
return cache.get(obj);
}
}
public class PermGenInternalizer implements Internalizer<String> {
@Override
public String get(String obj) {
return obj.intern();
}
}
Internalizer<String> internalizer = new LRUInternalizer(2048);
// ... get some object "input" that stream fields
for (String s : input.nextField()) {
s = internalizer.get(s);
// store s...
}
String a = SOME_RANDOM_VALUE
a.intern()
String a = SOME_RANDOM_VALUE.intern()
if (this == anObject) {
return true;
}
("a" + "b" + "c").intern() == "abc"
public class StringPool {
public static void main(String[] args) {
String a = "abc";
String b = "abc";
String c = new String("abc");
System.out.println(a);
System.out.println(b);
System.out.println(a == c);
}
}
#2 = String #32 // abc
[...]
#32 = Utf8 abc
0: ldc #2 // String abc
2: astore_1
3: ldc #2 // String abc
5: astore_2
6: new #3 // class java/lang/String
9: dup
10: ldc #2 // String abc
12: invokespecial #4 // Method java/lang/String."<init>":(Ljava/lang/String;)V
15: astore_3
16: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream;
19: aload_1
20: invokevirtual #6 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
23: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream;
26: aload_2
27: invokevirtual #6 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
30: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream;
33: aload_1
34: aload_3
35: if_acmpne 42
38: iconst_1
39: goto 43
42: iconst_0
43: invokevirtual #7 // Method java/io/PrintStream.println:(Z)V
private static WeakHashMap<String, WeakReference<String>> internStrings = new WeakHashMap<>();
public static String internalize(String k) {
synchronized (internStrings) {
WeakReference<String> weakReference = internStrings.get(k);
String v = weakReference != null ? weakReference.get() : null;
if (v == null) {
v = k;
internStrings.put(v, new WeakReference<String>(v));
}
return v;
}
}