问题
After executing String S1 = "hello";
JVM will create a String object in SCP and that object will hold an array of char in value
field like
s1.value = {'h', 'e', 'l', 'l', 'o'}
And when we say
String s2 = new String("hello");
And according to the source code of String
class after constructor execution s2.value
will also become "hello".value
which will be similar to s1.value
.
public String(String original) {
this.value = original.value;
this.hash = original.hash;
}
So every time we create String object using new
JVM will create
- one object in heap and
- one string literal object in SCP if it already not there
And the object in heap points to the literal object in SCP internally.
And every time, we make a change in s2
or in any other string (doesn't matter it is created from literal or using new
) one new string literal will get created on the heap, which that newly changed s2
will point.
Using String s2 = new String("hello")
is not creating "hello"
object in heap. JVM is creating "hello"
in SCP only if it is not present there and s2 pointing to it.
My question is not, what is the difference between new String("hello")
or simple "hello"
.
My question is when using public String(String original)
is just creating empty string object in heap and wasting memory Why Java allows developers to call public String(String original)
and why is it even provided in String class, what benefit it is giving?
回答1:
There is an interesting statement in Joshua Bloch’s “Effective Java”, 2nd edition, chapter 4, item 15:
A consequence of the fact that immutable objects can be shared freely is that you never have to make defensive copies (Item 39). In fact, you never have to make any copies at all because the copies would be forever equivalent to the originals. Therefore, you need not and should not provide a
clone
method or copy constructor (Item 11) on an immutable class. This was not well understood in the early days of the Java platform, so theString
class does have a copy constructor, but it should rarely, if ever, be used (Item 5).
(page 76 in my copy)
I think, Joshua Bloch can be seen as an authoritative source, especially as James Gosling, one of the Java inventors, has been cited saying, “I sure wish I had this book ten years ago…” (referring to the 1st edition from 2001).
So the existence of the String(String)
constructor can be seen as a design mistake, much as the parameterless String()
constructor. Note also the presence of the factory methods String.valueOf(char[])/ String.valueOf(char[],int,int) and String.copyValueOf(char[])/ String.copyValueOf(char[],int,int), whose naming suggests a fundamental difference that simply isn’t there. The immutable nature of String
mandates that all variants create a defensive copy of the provided array, to protect against subsequent modifications. So the behavior is exactly the same (the documentation tells this explicitly), whether you use valueOf
or copyValueOf
.
That said, there are some practical use cases, though not necessarily being within original intentions. Some of them are described in the answers to this question. As the new
operation guarantees to produce a new instance, it might be useful for any subsequent operation relying on a distinct identity, e.g. synchronizing on that instance (not that this was a good idea) or trying to recognize that instance via identity comparison to be sure that it doesn’t originate from an external source. E.g., you might want to distinguish between a property’s default value and a value that has been explicitly set. This, however, is of limited use as other code might not guaranty to maintain the object identity in its operations, even if the string contents doesn’t change. Or it might remember your special instance and reuse it, once it encountered the string.
Before Java 7, update 6, String
had an offset
and length
field, allowing a cheap substring
operation, referring to a range within the original array, without copying. This led to the scenario, that a (conceptually) small string could hold a reference to a rather large array, preventing its garbage collection. For the reference implementation (that shipped by Sun/later Oracle), recreating the string via the String(String)
constructor produced a String
with a fresh copy of the array, occupying only as much memory as needed. So this was a use case incorporating an implementation specific fix to an implementation specific problem…
Current Java releases do not maintain these offset
and length
fields, implying a potentially more expensive substring
operation, but no copying behavior in the String(String)
constructor anymore. This is the version, whose source code you have cited in the question. The older version can be found in this answer.
来源:https://stackoverflow.com/questions/40721145/does-use-of-new-stringhello-is-completely-useless-over-simple-hello-when