【问题标题】:Java String Constructor OptimizationJava 字符串构造函数优化
【发布时间】:2013-09-12 21:43:00
【问题描述】:

假设我有一个方法:

public String getString() {
    char[] array = new char[]{'a', 'b', 'c'};
    return new String(array);
}

数组是否仍然复制到 String 构造函数中,还是 Java 编译器足够聪明,可以识别数组中的元素不能更改,因此它只能引用数组?

谢谢

【问题讨论】:

  • 你可以看看String源代码。
  • 是的,我知道字符串源代码会复制数组。我想知道Java编译器是否可以覆盖它?
  • 你是指JIT编译器还是javac
  • 任何一个,我只想知道这种优化是否可以发生在管道中的任何地方。
  • 我没有办法证明这可以发生,但 Java 有一个称为“逃逸分析”的 JIT 优化。当分配给堆栈会更快时,这可用于避免分配给堆。由于 C++ 现在有移动构造函数,所以在编写代码时假设 Oracle 的某个人会解决这个问题并使用 Escape Analysis 来防止不必要的复制。不要预先优化。 docs.oracle.com/javase/7/docs/technotes/guides/vm/…

标签: java string optimization


【解决方案1】:

由于 java String 类是不可变的,因此构造函数必须复制数组。

否则有人可以持有对数组的引用并对其进行修改:

char[] array = new char[]{'a', 'b', 'c'};
String string = new String(array);

array[1] = 'd'; // array modification must NOT affect the string

【讨论】:

  • 从技术上讲,JIT 可以使用转义分析来确定没有其他人获得过char[],因此它可以使用第一个实例而不复制它。但是 afaik,没有 JIT 这样做。您无法在 javac 中执行此操作,因为您不知道 java.lang.String 将来会如何变化(尽管这种变化不太可能会破坏这种行为)。
【解决方案2】:

查看java.lang.String的来源:

/**
 * Allocates a new {@code String} so that it represents the sequence of
 * characters currently contained in the character array argument. The
 * contents of the character array are copied; subsequent modification of
 * the character array does not affect the newly created string.
 *
 * @param  value
 *         The initial value of the string
 */
public String(char value[]) {
    this.value = Arrays.copyOf(value, value.length);
}

编辑

另见java.util.Arrays 的来源,它调用System.arraycopy

【讨论】:

    【解决方案3】:

    答案应该很明显:要使String 保持不变,它必须防御性地复制数组。

    考虑这段代码:

    public String getString() {
        char[] array = new char[]{'a', 'b', 'c'};
        String s = new String(array); // abc
        array[0] = 'x';
        return s; // xbc 
    }
    

    如果数组没有被复制,则后备数组将会泄露,从而使字符串暴露于可变性。

    【讨论】:

      【解决方案4】:

      也看看这个构造器:

        153     public String(String original) {
        154         this.value = original`.value;
        155         this.hash = original.hash;
        156     }
      

      这将是一个字符串文字:

      "abc"
      

      这只是对 String(char[] value) 的调用,其中 a、b、c 作为 char 数组的元素传入。简而言之,String x = "abc" 只是编译器为您提供的语法糖,以解决您在上面所做的事情。

      【讨论】:

        【解决方案5】:

        如果你看到源代码,你就会得到答案。输入数组被复制而不被引用。以下是源代码:

        public String(char value[]) {
        this.offset = 0;
        this.count = value.length;
        this.value = StringValue.from(value);
        }
        
        static char[] from(char[] value) {
            return Arrays.copyOf(value, value.length);
        } 
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2015-09-18
          • 2023-03-20
          • 2011-08-20
          • 2014-11-21
          • 2011-02-16
          • 2012-09-07
          • 2021-02-10
          • 1970-01-01
          相关资源
          最近更新 更多