开发者

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 created String 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.

What is the difference between "text" and new String("text")?


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 and 3: the same ldc #2 constant is loaded (the literals)
  • 12: a new string instance is created (with #2 as argument)
  • 35: a and c are compared as regular objects with if_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.

  1. 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");

  2. 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.

  3. 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) or byte[](after java 9 short to read).

  4. String literals are stored in StringPool and String Objects are stored in as usual heap Object Area.

  5. 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

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜