使用java.lang.String.intern()是否是一种良好的做法?

使用java.lang.String.intern()是否是一种良好的做法?,java,string,Java,String,Javadoc没有给出太多细节。(简而言之:它返回字符串的规范表示形式,允许使用==比较插入的字符串) 我什么时候会使用这个函数来支持String.equals() Javadoc中是否有未提及的副作用,即JIT编译器或多或少的优化 String.intern()还有其他用法吗 我什么时候会使用这个函数来表示String.equals() 当您需要速度时,因为您可以通过引用比较字符串(=比等于快) Javadoc中是否没有提到副作用 主要缺点是,您必须记住确保实际执行intern()所有要比

Javadoc没有给出太多细节。(简而言之:它返回字符串的规范表示形式,允许使用
==
比较插入的字符串)

  • 我什么时候会使用这个函数来支持
    String.equals()
  • Javadoc中是否有未提及的副作用,即JIT编译器或多或少的优化
  • String.intern()
    还有其他用法吗
我什么时候会使用这个函数来表示String.equals()

当您需要速度时,因为您可以通过引用比较字符串(=比等于快)

Javadoc中是否没有提到副作用

主要缺点是,您必须记住确保实际执行intern()所有要比较的字符串。很容易忘记对所有字符串进行intern(),然后可能会得到令人困惑的错误结果。另外,为了每个人的利益,请确保非常清楚地记录您所依赖的字符串是内部化的

如果决定内部化字符串,第二个缺点是intern()方法相对昂贵。它必须管理唯一字符串的池,以便进行相当多的工作(即使字符串已经内部化)。所以,在你的代码设计中要小心,这样你就不用再担心输入中所有合适的字符串了

(来自JGuru)

第三个缺点(仅限于Java7或更低版本):插入的字符串位于PermGen空间中,该空间通常非常小;您可能会遇到OutOfMemoryError,其中有大量可用堆空间


(来自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;
    }
}