Strings Are Objects in Java, So Why Don't We Use 'New' to Create Them

Strings are objects in Java, so why don't we use 'new' to create them?

In addition to what was already said, String literals [ie, Strings like "abcd" but not like new String("abcd")] in Java are interned - this means that every time you refer to "abcd", you get a reference to a single String instance, rather than a new one each time. So you will have:

String a = "abcd";
String b = "abcd";

a == b; //True

but if you had

String a = new String("abcd");
String b = new String("abcd");

then it's possible to have

a == b; // False

(and in case anyone needs reminding, always use .equals() to compare Strings; == tests for physical equality).

Interning String literals is good because they are often used more than once. For example, consider the (contrived) code:

for (int i = 0; i < 10; i++) {
System.out.println("Next iteration");
}

If we didn't have interning of Strings, "Next iteration" would need to be instantiated 10 times, whereas now it will only be instantiated once.

Is it better to create a string in Java as an object or as a primitive type?

My understanding of strings in Java is that they can be either primitive types or objects

Wrong. Strings are always objects. Its just that String literals ("someStringHere") are treated in a special manner by the compiler and then interned by the JVM.

If your question is whether -

String s = "Abc";

is better than

String s = new String("Abc");,

Yes, since the second one is redundant and creates 2 Strings (one in constants pool and another on heap).

Why new keyword not needed for String

With the following line you are not creating a new String object in the heap but reusing a string literal (if already available):

String message = "Hai";

"Hai" is a string literal in the string literal pool. Since, strings are immutable, they are reusable so they are pooled in the string literal pool by the JVM. And this is the recommended way, because you are reusing it.

But, with the following you are actually creating a new object (in the heap):

String message = new String("Hai");

new String("Hai") is a new String object. In this case, even if the literal "Hai" was already in the string literal pool, a new object is created. This is not recommended because chances are that you might end with more than one String objects with the same value.

Also see this post: Questions about Java's String pool

Are there other classes which do not require new to create object ??

Actually, you can not create any object in Java without using the keyword new.

e.g.

Integer i = 1;

Does, not mean that the Integer object is created without using new. It's just not required for us to use the new keyword explicitly. But under the hood, if the Integer object with value 1 does not already exist in cache (Integer objects are cached by JVM), new keyword will be used to create it.

Can new objects be instantiated without the = new Obj ()?

So String isn't a primitive type but rather a class and objects of classes have to be created in the form Obj x = new Obj (); usually. However, strings can be created by saying String x = "..."; and this is the preferred way rather than String x = new String ("...");

That's correct, it often a mistake to use new String(String). Since Strings are such a common type of value to create that Java, like most languages, has a string literal grammar construct. When evaluated the string literal expression returns a string instance representing the text.

Calling String y = new String("...") is roughly equivalent to String x = "..."; String y = new String(x);: the string literal evaluated to a string which was then supplied to a String constructor that returned a new string instance (albeit using the same backing character array to avoid copying data) - such a waste! As such the new String(String) constructor should probably "never" be called, with the exception of wishing to do something special wrt. string interning.

So I was wondering why this is allowed for strings and would it be possible to create objects of other classes in a similar fashion if the constructor only required a single parameter.

It is a special aspect of Java grammar, and most other languages, to create string objects with minimal fuss. It would be very annoying to have to create strings out of other values: new String(new char[] {'n','o',' ','t','h','a','n','k','s'}).

Java does not have support for custom parsing and thus it is not possible to extend this behavior to custom types in Java itself. The grammar of string literals (and behavior during execution) is covered in the Java Language Specification.

The very creation of string objects from string literals is largely "JVM magic / implementation details" (creation of strings from literals do not call the new String(String) constructor as then, how is the original string instance created?). Furthermore, the string object instances returned from evaluating string literals are not guaranteed to be unique / "new" per string interning rules.

For example if a class had a constructor that only called one integer, would saying Obj x = 2; be syntactically correct because it has the object name and parameter still included in the same way that Strings are written.

This is not how Java works. A language that did work as hypothesized would not be Java 8.

In this example the integer literal is 2: when evaluated as an expression it yields the value .. (int)2. Unlike with the case of a string literal, Java then performs an Integer autoboxing operation: 2 is an int which, unlike String, is not an Object and cannot be directly assigned. This makes the original similar to Object x = new Integer(2); where the int-value has been implicitly wrapped as an Integer-value.

Every time I use String, does it create a new String object?

No. String constants are interned automatically, so any identical string literals all reference the same object in memory.

Some more information on this: http://www.xyzws.com/Javafaq/what-is-string-literal-pool/3

An example of this:

String s1 = "Test";
String s2 = "Test";
String s3 = new String("Test");
s1 == s2;//Evaluates to true, because they are the same object (both created with string literals)
s1 == s3;//Evaluates to false, because they are different objects containing identical data

What is the difference between String initializations by new String() and new String( ) in Java?

Well, they are almost the same.

public static void main(String[] args) {
String s1 = new String();
String s2 = new String("");
System.out.println(s1.equals(s2)); // returns true.
}

Minor differences (rather insignificant) :

  1. new String(); takes less time to execute than new String(""); because the copy constructor does a lot of stuff.

  2. new String("") adds the empty String ("") to the String constants pool if it is not already present.

Other than this, there are no other differences

Note : The use of new String("abc") is almost always bad because you will be creating 2 Strings one on String constants pool and another on heap with the same value.

What is the purpose of the expression new String(...) in Java?

The one place where you may think you want new String(String) is to force a distinct copy of the internal character array, as in

small=new String(huge.substring(10,20))

However, this behavior is unfortunately undocumented and implementation dependent.

I have been burned by this when reading large files (some up to 20 MiB) into a String and carving it into lines after the fact. I ended up with all the strings for the lines referencing the char[] consisting of entire file. Unfortunately, that unintentionally kept a reference to the entire array for the few lines I held on to for a longer time than processing the file - I was forced to use new String() to work around it, since processing 20,000 files very quickly consumed huge amounts of RAM.

The only implementation agnostic way to do this is:

small=new String(huge.substring(10,20).toCharArray());

This unfortunately must copy the array twice, once for toCharArray() and once in the String constructor.

There needs to be a documented way to get a new String by copying the chars of an existing one; or the documentation of String(String) needs to be improved to make it more explicit (there is an implication there, but it's rather vague and open to interpretation).

Pitfall of Assuming what the Doc Doesn't State

In response to the comments, which keep coming in, observe what the Apache Harmony implementation of new String() was:

public String(String string) {
value = string.value;
offset = string.offset;
count = string.count;
}

That's right, no copy of the underlying array there. And yet, it still conforms to the (Java 7) String documentation, in that it:

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.

The salient piece being "copy of the argument string"; it does not say "copy of the argument string and the underlying character array supporting the string".

Be careful that you program to the documentation and not one implementation.

Why to create a String object using new

The basic difference between them is memory allocation.

First option i.e

String s1 = "hello";

When you use this s1 is called as a string literal and memory for s1 is allocated at compile time.

But in 2nd case

String s2 = new String("hello");

In this case s2 is called as an object of String representing hello

When you tries to create two string literal using the first case, only one memory is referenced by those two literals. I mean String literals are working with a concept of string pool. when you create a 2nd string literal with same content, instead of allocating a new space compiler will return the same reference. Hence you will get true when you compare those two literals using == operator.

But in the 2nd case each time JVM will create a new object for each. and you have to compare their contents using equals() method but not with == operator.

If you want to create a new string object using 2nd case and also you don't want a new object, then you can use intern() method to get the same object.

String s = "hello";
String s1 = new String("hello").intern();
System.out.println(s == s1);

In this case instead of creating a new object, JVM will return the same reference s. So the output will be true



Related Topics



Leave a reply



Submit