What is the difference between "text" and new String("text")?
Wh开发者_开发技巧at is the difference between these two following statements?
String s = "text";
String s = new String("text");
new String("text");
explicitly creates a new and referentially distinct instance of a String
object; String s = "text";
may reuse an instance from the string constant pool if one is available.
You very rarely would ever want to use the new String(anotherString)
constructor. From the API:
String(String original)
: Initializes a newly createdString
object so that it represents the same sequence of characters as the argument; in other words, the newly created string is a copy of the argument string. Unless an explicit copy of original is needed, use of this constructor is unnecessary since strings are immutable.
Related questions
- Java Strings: “String s = new String(”silly“);”
- Strings are objects in Java, so why don’t we use ‘new’ to create them?
What referential distinction means
Examine the following snippet:
String s1 = "foobar";
String s2 = "foobar";
System.out.println(s1 == s2); // true
s2 = new String("foobar");
System.out.println(s1 == s2); // false
System.out.println(s1.equals(s2)); // true
==
on two reference types is a reference identity comparison. Two objects that are equals
are not necessarily ==
. It is usually wrong to use ==
on reference types; most of the time equals
need to be used instead.
Nonetheless, if for whatever reason you need to create two equals
but not ==
string, you can use the new String(anotherString)
constructor. It needs to be said again, however, that this is very peculiar, and is rarely the intention.
References
- JLS 15.21.3 Reference Equality Operators == and !=
class Object
-boolean Object(equals)
Related issues
- Java String.equals versus ==
- How do I compare strings in Java?
String literals will go into String Constant Pool.
The below snapshot might help you to understand it visually to remember it for longer time.
Object creation line by line:
String str1 = new String("java5");
Using string literal "java5" in the constructor, a new string value is stored in string constant pool. Using new operator, a new string object is created in the heap with "java5" as value.
String str2 = "java5"
Reference "str2" is pointed to already stored value in string constant pool
String str3 = new String(str2);
A new string object is created in the heap with the same value as reference by "str2"
String str4 = "java5";
Reference "str4" is pointed to already stored value in string constant pool
Total objects : Heap - 2, Pool - 1
Further reading on Oracle community
One creates a String in the String Constant Pool
String s = "text";
the other one creates a string in the constant pool ("text"
) and another string in normal heap space (s
). Both strings will have the same value, that of "text".
String s = new String("text");
s
is then lost (eligible for GC) if later unused.
String literals on the other hand are reused. If you use "text"
in multiple places of your class it will in fact be one and only one String (i.e. multiple references to the same string in the pool).
JLS
The concept is called "interning" by the JLS.
Relevant passage from JLS 7 3.10.5:
Moreover, a string literal always refers to the same instance of class String. This is because string literals - or, more generally, strings that are the values of constant expressions (§15.28) - are "interned" so as to share unique instances, using the method String.intern.
Example 3.10.5-1. String Literals
The program consisting of the compilation unit (§7.3):
package testPackage; class Test { public static void main(String[] args) { String hello = "Hello", lo = "lo"; System.out.print((hello == "Hello") + " "); System.out.print((Other.hello == hello) + " "); System.out.print((other.Other.hello == hello) + " "); System.out.print((hello == ("Hel"+"lo")) + " "); System.out.print((hello == ("Hel"+lo)) + " "); System.out.println(hello == ("Hel"+lo).intern()); } } class Other { static String hello = "Hello"; }
and the compilation unit:
package other; public class Other { public static String hello = "Hello"; }
produces the output:
true true true true false true
JVMS
JVMS 7 5.1 says:
A string literal is a reference to an instance of class String, and is derived from a CONSTANT_String_info structure (§4.4.3) in the binary representation of a class or interface. The CONSTANT_String_info structure gives the sequence of Unicode code points constituting the string literal.
The Java programming language requires that identical string literals (that is, literals that contain the same sequence of code points) must refer to the same instance of class String (JLS §3.10.5). In addition, if the method String.intern is called on any string, the result is a reference to the same class instance that would be returned if that string appeared as a literal. Thus, the following expression must have the value true:
("a" + "b" + "c").intern() == "abc"
To derive a string literal, the Java Virtual Machine examines the sequence of code points given by the CONSTANT_String_info structure.
If the method String.intern has previously been called on an instance of class String containing a sequence of Unicode code points identical to that given by the CONSTANT_String_info structure, then the result of string literal derivation is a reference to that same instance of class String.
Otherwise, a new instance of class String is created containing the sequence of Unicode code points given by the CONSTANT_String_info structure; a reference to that class instance is the result of string literal derivation. Finally, the intern method of the new String instance is invoked.
Bytecode
It is also instructive to look at the bytecode implementation on OpenJDK 7.
If we decompile:
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);
}
}
we have on the constant pool:
#2 = String #32 // abc
[...]
#32 = Utf8 abc
and main
:
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
Note how:
0
and3
: the sameldc #2
constant is loaded (the literals)12
: a new string instance is created (with#2
as argument)35
:a
andc
are compared as regular objects withif_acmpne
The representation of constant strings is quite magic on the bytecode:
- it has a dedicated CONSTANT_String_info structure, unlike regular objects (e.g.
new String
) - the struct points to a CONSTANT_Utf8_info Structure that contains the data. That is the only necessary data to represent the string.
and the JVMS quote above seems to say that whenever the Utf8 pointed to is the same, then identical instances are loaded by ldc
.
I have done similar tests for fields, and:
static final String s = "abc"
points to the constant table through the ConstantValue Attribute- non-final fields don't have that attribute, but can still be initialized with
ldc
Conclusion: there is direct bytecode support for the string pool, and the memory representation is efficient.
Bonus: compare that to the Integer pool, which does not have direct bytecode support (i.e. no CONSTANT_String_info
analogue).
Any String literal gets created inside string literal pool and the pool doesn't allow any duplicates. Thus if two or more string objects are initialized with the same literal value then all objects will point to the same literal.
String obj1 = "abc";
String obj2 = "abc";
"obj1" and "obj2" will point to the same string literal and the string literal pool will have only one "abc" literal.
When we create a String class object using the new keyword the string thus created is stored in heap memory. Any string literal passed as parameter to the constructor of String class however is stored in string pool. If we create multiple objects using the same value with the new operator a new object will be created in the heap each time, because of this new operator should be avoided.
String obj1 = new String("abc");
String obj2 = new String("abc");
"obj1" and "obj2" will point to two different objects in the heap and the string literal pool will have only one "abc" literal.
Also something that is worth noting with regards to the behavior of strings is that any new assignment or concatenation done on string creates a new object in memory.
String str1 = "abc";
String str2 = "abc" + "def";
str1 = "xyz";
str2 = str1 + "ghi";
Now in the above case:
Line 1: "abc" literal is stored in string pool.
Line 2: "abcdef" literal gets stored in the string pool.
Line 3: A new "xyz" literal is stored in the string pool and "str1" starts to point to this literal.
Line 4: Since the value is generated by appending to another variable the result is stored in the heap memory and the literal being appended "ghi" will be checked for its existence in the string pool and will be created since it doesn't exist in the above case.
@Braj : i think u have mentioned the other way around. Please correct me if i am wrong
Object creation line by line:
String str1 = new String("java5")
Pool- "java5" (1 Object)
Heap - str1 => "java5" (1 Object)
String str2 = "java5"
pool- str2 => "java5" (1 Object)
heap - str1 => "java5" (1 Object)
String str3 = new String(str2)
pool- str2 => "java5" (1 Object)
heap- str1 => "java5", str3 => "java5" (2 Objects)
String str4 = "java5"
pool - str2 => str4 => "java5" (1 Object)
heap - str1 => "java5", str3 => "java5" (2 Objects)
Think of "bla"
being a magic factory like Strings.createString("bla")
(pseudo). The factory holds a pool of all strings yet created this way.
If it gets invoked, it checks if there is already string in the pool with this value. If true, it returns this string object, hence to strings obtained this way are indeed the same object.
If not, it creates a new string object internally, saves it in the pool and then returns it. Thus, when the same string value is queried the next time, it returns the same instance.
Manually creating new String("")
overrides this behaviour by bypassing the string literal pool. So equality should always be checked using equals()
which compares the character sequence instead of the object reference equality.
One simple way to understand the difference is below:-
String s ="abc";
String s1= "abc";
String s2=new String("abc");
if(s==s1){
System.out.println("s==s1 is true");
}else{
System.out.println("s==s1 is false");
}
if(s==s2){
System.out.println("s==s2 is true");
}else{
System.out.println("s==s2 is false");
}
output is
s==s1 is true
s==s2 is false
Thus new String() will always create a new instance.
Although it looks the same from a programmers point of view, it has big performance impact. You would want to use the first form almost always.
String str = new String("hello")
It will check whether String constant pool already contains String "hello"? If present then it will not add an entry in String constant pool. If not present then it will add an entry in String constant pool.
An object will be created in a heap memory area and str
reference points to object created in heap memory location.
if you want str
reference to point object containing in String constant pool then one has to explicitly call str.intern();
String str = "world";
It will check whether String constant pool already contains String "hello"? If present then it will not add an entry in String constant pool. If not present then it will add an entry in String constant pool.
In both the above case, str
reference points to String "world"
present in Constant pool.
When you store a String as
String string1 = "Hello";
directly, then JVM creates a String object with the given price during a separate block of memory called String constant pool.
And whenever we have a tendency to try and produce another String as
String string2 = "Hello";
JVM verifies whether or not any String object with constant price exists within the String constant pool, if so, rather than making a brand new object JVM assigns the reference of the existing object to the new variable.
And when we store String as
String string = new String("Hello");
using the new keyword, a brand new object with the given price is made no matter the contents of the String constant pool.
Sorry for late Answer but much needed Answer. First we need to know some Java.lang.String Class rules.
String Literals e.g.
String str="java";
(we use only double Quotes) are different from String Object (we use new keyword) e.g.String str=new String("java");
String is Immutable Object i.e. If value changes a new Object is created and returned to you eg See
replace() and replaceAll()
functions and many more.This creates a problem of many String Object in Modification, So creators of Java came up an Idea was called StringPool. StringPool is stored in heap area where object reference data will be stored as we know String is
Char[]
(before java 9 very Long to read) orbyte
[](after java 9 short to read).String literals are stored in StringPool and String Objects are stored in as usual heap Object Area.
If there are many Object String Initialization JVM heap will be finished in String Operations only, Java Development team came up with intern() solution this moves/changes memory reference to StringPool.
Program: Comparing String references to objects
Another good link to understand java.lang.String better
import java.util.*;
class GFG {
public static void main(String[] args)
{
String siteName1 = "java.com";
String siteName2 = "java.com";
String siteName3 = new String("java.com");
String siteName4 = new String("java.com").intern();
System.out.println("siteName1:::"+Integer.toHexString(System.identityHashCode(siteName1)));
System.out.println("siteName2:::"+Integer.toHexString(System.identityHashCode(siteName2)));
System.out.println("siteName3 creation Of New Object Without Interned:::"+Integer.toHexString(System.identityHashCode(siteName3)));//must be Diffrent bcoz new Object In Heap Area
System.out.println("siteName4 creation Of New Object With Interned:::"+Integer.toHexString(System.identityHashCode(siteName4)));//must be same MemoryAddress of siteName1,siteName2 and Interned, bcoz Objects Points to String pool Now
System.out.println(siteName1 == siteName2); // true
System.out.println(siteName1 == siteName3); // false this tells about lietral vs String Objects
String siteName5 = siteName3.intern(); // Interning will not change Original Object but gives us a new Object
System.out.println("siteName5 Interned from siteName3:::"+Integer.toHexString(System.identityHashCode(siteName5)));//must be same MemoryAddress of siteName1,siteName2 and Interned, bcoz Objects Points to String pool Now
System.out.println(siteName1 == siteName3); // false this tells about Immutability
System.out.println(siteName1 == siteName5); // true After Intering both are same
System.out.println(siteName1 == siteName4); // true
System.out.println(siteName5 == siteName4); // true
}
}
When you use some thing like new String("Hello World")
the SpotBugs code analyze tool, complains a performance issue.
The description of this issue shows deference of new
and constant string
Using the
java.lang.String(String)
constructor wastes memory because the object so constructed will be functionally indistinguishable from the String passed as a parameter. Just use the argument String directly.
Bug kind and pattern: Dm - DM_STRING_CTOR
精彩评论