2

Say I have a method:

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

Is the array still copied in the String constructor or is the Java compiler smart enough to recognize that the elements in the array cannot change so it can just reference the array?

Thanks

5
  • 2
    You could have a look at the String source code. Commented Sep 12, 2013 at 13:36
  • Yes, I know the String source code will copy the array. I am wondering if the Java compiler can override that? Commented Sep 12, 2013 at 13:37
  • Do you mean the JIT compiler or javac? Commented Sep 12, 2013 at 13:43
  • Either one, i just want to know if this optimization can occur anywhere in the pipeline. Commented Sep 12, 2013 at 13:44
  • I don't have a way of proving that this can take place, but Java has a JIT optimization called "Escape Analysis". This can be used to avoid allocating to the heap when an allocation to the stack would be faster. Since C++ now has move-constructors, write your code with the assumption that someone at Oracle will figure this out and use Escape Analysis to prevent unnecessary copies. Don't pre-optimize. docs.oracle.com/javase/7/docs/technotes/guides/vm/… Commented Mar 3, 2017 at 16:17

5 Answers 5

6

Since the java String class is immutable the constructor must copy the array.

Otherwise someone can hold a reference to the array and modify it:

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

array[1] = 'd'; // array modification must NOT affect the string
Sign up to request clarification or add additional context in comments.

1 Comment

Technically, the JIT could use escape analysis to determine that nobody else ever gets the char[] so that it could use that first instance without copying it. But afaik, no JIT does this. You wouldn't be able to do it at javac because you don't know how java.lang.String will change in the future (unlikely though it is that such a change would break this behavior).
4

See the source of 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);
}

Edit:

See also the source of java.util.Arrays which calls System.arraycopy.

Comments

1

The answer should be obvious: For String to remain immutable, it must defensively copy the array.

Consider this code:

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

If the array is not copied, the backing array will have leaked out, exposing the String to mutability.

Comments

1

Look at this contructor too:

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

This would be a string literal:

"abc"

Which is just a call to String(char[] value) with a, b, c passed in as elements of a char array. In short, String x = "abc" is just syntactic sugar that compiler provides you to get around what you are doing above.

Comments

0

If you see the source code, you will get your answer. The input array is copied and not referenced. Here is the source code:

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);
} 

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.