Java - How to assign/copy a String content inside a function - java

Ok, I know that String objects are immutable, so if I need to "copy" the string content from a given string A to another one B I can assign the reference to A like (method 1):
String B = A;
instead of (method 2)
String B = new String(A);
because since there's no way to modify A I'm sure that by referring to B I obtain the same character sequence. Right?
But what happens in this situation described below?
I have a class C that has a String field "subject" and a constructor that take as argument a String "arg" and it must initialize subject to a character sequence equal to the one of "arg".
I have the following code:
public C getSomeC(...){
// some code to set the String A that is defined inside this function
return new C(A);
}
This way I simply call getSomeC(.) from some other point in my program so as to get my C instance.
But what changes whether I use method 1 or 2 in the constructor of C to define C.subject?
If I use the method 1 I pass to C constructor by value the reference of A and I assign to subject the reference to A right? But A has a visibility limited to method getSomeC(..) While I want my C instance to be used outside that method. What happens inside java in this case? Does the reference A be destroyed at the end of getSomeC(.) while the object remains alive because referred by instanceofC.subject?
What if I use method 2 instead?

In short, both methods are fine, your String will be kept, but you should prefer method 1 as it does not create unnecessary objects, as #Paul pointed out.
But A has a visibility limited to method getSomeC(..)
The variable A has this visibility, not the object pointed by A.
What happens inside java in this case? Does the reference A be
destroyed at the end of getSomeC(.) while the object remains alive
because referred by instanceofC.subject?
The String object will exist outside of the method's scope, as long as some reference to it is kept somewhere. And this is the case.
Indeed, a reference is kept in your C object, that's why you're fine.

You are confusing variable scope with object lifetime. Your variable A is only visible inside getSomeC(). But the strin object that variable points to is not applicable from garbage collection until it is not referenced anymore. So, if you pass it to teh constructor and assign it to a field, that field still point to the string object and it persists.
Besides that I'd prefer the first method. String B = new String(A); explicitly creates a new string object that represents the same value. With String B = A; you'll only have one object and save memory. It might not seem much but in big systems or if you do this in many iterations, this can make a difference.

I'm not sure I understand your last paragraph. However, there is basically no reason to ever use: String newString = new String(oldString);. You can always just use: String newString = olString;. (The inclusion of a constructor taking a String and returning a new String that is a copy of the original has been considered a mistake by many since, being immutable, is it better to just reuse the original String.)
The only exception would be if forced to deal with dodgy code relying on the identity (rather than the value) of a String.

You are right - strings are immutable in Java. Which means, that everytime you do something with string a new string with new contents is created.
The only difference is that when you explicitly call new operator it creates a brand new String, which is not taken from so-called "string pool".
E.g.:
"A" == "A"
can be true (not guaranteed, though), but
"A" == new String("A")
is always false.

Related

Java - copying a variable's value instead of referencing it

I know this is a basic Java question yet I have never seen a full solution to this problem. Basically, I want to copy another variable's value into another variable and then have the newly created variable preserve that value.
Here is my code :
private void someMethod() {
String tmpCommand = commandName;
commandName = modelItem.getName();
}
Here, tmpCommand's value will change to modelItem.getName() value since it references commandName
. However, what if I want tmpCommand to not change value whenever commandName value is changed? Would I have to create a new object tmpCommand?
Here, if tmpCommand's value will change to modelItem.getName() value since it references commandName.
No, it won't. The value of tmpCommand is just the value of commandName at the time of the assignment.
That's really simple to demonstrate:
String original = "foo";
String test = original;
original = "bar";
System.out.println(test); // Prints foo
Note that changing the value of original is not the same as changing the data within the object that the value of original refers to. Let's do a different example with a mutable type - StringBuilder:
StringBuilder original = new StringBuilder("foo");
String test = original;
original.append("bar");
System.out.println(test); // Prints foobar
Here, both test and original still have the same value: that value is a reference to a StringBuilder object. The call to append doesn't change that reference at all... it changes the data in the object that the reference refers to. It's really important to differentiate between variables, references and objects.
So if you want to avoid that, you'll need to create a new object with the same content - some classes provide a way of doing that; others don't. For example, you could use:
StringBuilder original = new StringBuilder("foo");
String test = new StringBuilder(original);
original.append("bar");
System.out.println(test); // Prints foo
When a clone() method is provided, that could be used too. But basically the idea is that sometimes you want two variables to hold references to independent objects.
Your code will work as it is, since once commandName is assigned modelItem.getName(), it no longer refers to the same object as tmpCommand. That said, Strings are immutable, so you couldn't change the contents of these objects anyway.

How should I copy Strings in Java?

String s = "hello";
String backup_of_s = s;
s = "bye";
At this point, the backup variable still contains the original value "hello" (this is because of String's immutability right?).
But is it really safe to copy Strings with this method (which is of course not safe to copy regular mutable objects), or is better to write this? :
String s = "hello";
String backup_of_s = new String(s);
s = "bye";
In other words, what's the difference (if any) between these two snippets?
EDIT - the reason why the first snippet is safe:
Let me just explain things with a little more detail, based on the good answers already provided (which were essentially focused on the question of difference of performance between the 2 snippets):
Strings are immutable in Java, which means that a String object cannot be modified after its construction.
Hence,
String s = "hello"; creates a new String instance and assigns its address to s (s being a reference to the instance/object)
String backup_of_s = s; creates a new variable backup_of_s and initializes it so that it references the object currently referenced by s.
Note: String immutability guarantees that this object will not be modified: our backup is safe
Note 2: Java garbage collection mechanism guarantees that this object will not be destroyed as long as it is referenced by at least one variable (backup_of_s in this case)
Finally, s = "bye"; creates another String instance (because of immutability, it's the only way), and modifies the s variable so that it now references the new object.
Since strings are immutable, both versions are safe. The latter, however, is less efficient (it creates an extra object and in some cases copies the character data).
With this in mind, the first version should be preferred.
Strings are immutable objects so you can copy them just coping the reference to them, because the object referenced can't change ...
So you can copy as in your first example without any problem :
String s = "hello";
String backup_of_s = s;
s = "bye";
Your second version is less efficient because it creates an extra string object when there is simply no need to do so.
Immutability means that your first version behaves the way you expect and is thus the approach to be preferred.
Second case is also inefficient in terms of String pool, you have to explicitly call intern() on return reference to make it intern.
String str1="this is a string";
String str2=str1.clone();
How about copy like this?
I think to get a new copy is better, so that the data of str1 won't be affected when str2 is reference and modified in futher action.

Java immutable strings confusion

If Strings are immutable in Java, then how can we write as:
String s = new String();
s = s + "abc";
Strings are immutable.
That means that an instance of String cannot change.
You're changing the s variable to refer to a different (but still immutable) String instance.
Your string variable is NOT the string. It's a REFERENCE to an instance of String.
See for yourself:
String str = "Test String";
System.out.println( System.identityHashCode(str) ); // INSTANCE ID of the string
str = str + "Another value";
System.out.println( System.identityHashCode(str) ); // Whoa, it's a different string!
The instances the str variable points to are individually immutable, BUT the variable can be pointed to any instance of String you want.
If you don't want it to be possible to reassign str to point to a different string instance, declare it final:
final String str = "Test String";
System.out.println( System.identityHashCode(str) ); // INSTANCE ID of the string
str = str + "Another value"; // BREAKS HORRIBLY
The first answer is absolutely correct. You should mark it as answered.
s = s+"abc" does not append to the s object. it creates a new string that contains the characters from the s object (of which there are none) and "abc".
if string were mutable. it would have methods like append() and other such mutating methods that are on StringBuilder and StringBuffer.
Effective Java by Josh Bloch has excellent discussion on immutable objects and their value.
Immutable Classes are those whose methods can change their fields, for example:
Foo f = new Foo("a");
f.setField("b"); // Now, you are changing the field of class Foo
but in immutable classes, e.g. String, you cannot change the object once you create it, but of course, you can reassign the reference to another object. For example:
String s = "Hello";
s.substring(0,1); // s is still "Hello"
s = s.substring(0,1); // s is now referring to another object whose value is "H"
String s = new String();
Creates a new, immutable, empty string, variable "s" references it.
s = s+"abc";
Creates a new, immutable, string; the concatenation of the empty string and "abc", variable "s" now references this new object.
Just to clarify, when you say s = s+"abc";
That means, create a new String instance (which is composed of s and "abc") then assign that new String instance to s. So the new reference in s is different from the old.
Remember, a variable is effectively a reference to an object at some specific memory location. The object at that location stays at that location, even if you change the variable to refer to a new object at a different location.
String s = new String();
An empty String object ("") is created. And the variable s refers to that object.
s = s + "abc";
"abc" is a string literal (which is nothing but a String object, which is implicitly created and kept in a pool of strings) so that it can be reused (since strings are immutable and thus are constant). But when you do new String() is totally different because you are explicitly creating the object so does not end up in the pool. You can throw is in the pool by something called interning.
So, s + "abc" since at this point concatenation of and empty string ("") and "abc" does not really create a new String object because the end result is "abc" which is already in the pool. So, finally the variable s will refer to the literal "abc" in the pool.
I believe you are all making this much more complicated than it needs to be, and that simply confuses people who are trying to learn!
The primary benefit of making an object immutable in Java is that it can be passed by reference (e.g. to another method or assigned using the assignment operator) without having to worry about downstream changes to the object causing issues in the current method or context. (This is very different than any conversation about the thread safety of an object.)
To illustrate, create an application that passes a String as a parameter to a separate method, and modify the String in that method. Print the String at the end of the called method and then after control returns to the calling method. The Strings will have different values, and that's because they point to different memory locations, a direct result of "changing" the immutable String (creating a new pointer and pointing it to a new value behind the scenes). Then create an application that does the same things except with StringBuffer, which is not immutable. (For example, you can append to the StringBuffer to modify it.) The printed StringBuffers will have the same values, and that is because it is (a) being passed by reference, as Java does with all objects passed to methods as parameters and (b) mutable.
I hope this helps folks who are reading this thread and trying to learn!

Java String class instances are constants

this is probably an easy question but not for me at this stage.
I read that (I quote) "All instances of the String class are constants, meaning they cannot be changed after they have been created. But strings can be replaced".
This is confusing. What does it mean that a String variable cannot be changed but the string can?
Can anyone please give me code example where we would try to change the variable but fail?
Cheers for the help.
When you write:
String myString = "Hi!";
You're doing two things. The first one is defining a reference called myString the second one is creating a String Object. That String Object contains "Hi!", and there isn't a way to change that. In other words, there isn't a set method to change the string:
myString.set("another content");
However, you can create a new Object and change your myString reference to point to it. The important thing to get is that your myString isn't the String Object itself but just a reference to it.
myString = "New content";
When you do that, the old String is not pointed by any variable any more and is a candidate for garbage collection. Also any other operation on the String, such as substring, uppercase, etc. will create a new String Object.
When an Object can't be changed after being created is called Immutable. In Java Strings are not only immutable, but also final, so that you can't subclass a String to change its behaviour.
Strings aren't constants, they're immutable, which is something else altogether. It means that you cannot modify the contents of string object, but you can make a new one based on the first, e.g.
String hw = "hello world";
hw.ToUpperCase();
The latter doesn't change the original string hw but creates a new string with all characters to uppercase.
What does it mean that a String variable cannot be changed but the string can?
Actually the text that you quoted means the exact opposite of that.
A String variable can be assigned to (i.e. replaced). Example is:
String s = "first";
s = "second";
This replaces the reference to "first" with a reference to "second".
I can't give you a legitimate example of changing the contents / state of a String because you can't do it*.
* Actually, you can do it by breaking a String object's encapsulation using reflection. But it is a really, really bad idea.
The answer to the question is this: in Java string literal is an immutable object.
As previously stated by fellow programmers - you may change the reference, yes, but you may never change an immutable object (it is guaranteed not to be possible to change it).

Strings memory model

What I read about strings is when a string object is created in Java it is immutable. For example:
String s=new String();
s="abc";
s="xyz";
Does the String s no longer point to "abc"?
And another thing: what is size of s;
Is the String object analogous to a char* pointer in C in terms of the memory model?
No, Java String is not as char* in C. If you are looking for the analogue char[] in java is something like this.
String is a class that wraps char array and provides a lot of functionality. Moreover it is immutable, i.e. you cannot change its content. You can only create another string. Additionally String is final, so you cannot subclass it.
String is special class. Only string supports operator (+). All other classes do not support operators at all, even primitive wrappers (Integer, Double etc). Presence of string constant in code "foobar" invokes java.lang.String constructor.
Yes, Strings in Java are immutable. That is to say, the content pointed too by a string variable cannot be changed after it has been initialized. Using your own examples to illustrate:
String s=new String();
In the above code, you have created a new, empty String and assigned it to the s variable.
s="abc";
You have created another new String, this time with content "abc". You have set the variable s to point to this new String. Your previous, empty string will get garbage collected at some point in the future.
s="xyz";
Similar to above. You have created another new String, with content "xyz", and set the variable s to point to it. The previous "abc" string will get garbage collected at some point in the future.
Note that at no point did you actually modify the empty string to become "abc", or modify the "abc" string to become "xyz". All operations on String that concatenate, convert case, or otherwise appear to modify the String actually return a new String with the function results. To illustrate:
String s = new String("Hello");
String b = s.concat(" World");
System.out.println(s); // This will NOT produce 'Hello World'
System.out.println(b); // Whereas, this will
As to the last part of your question, you would use the length() function to determine the 'size' of your string. Note that this is based on Unicode encoding, and might not be what you expect the length to be as defined in ANSI C.
Que: Does the String s no longer point to "abc"?
Ans: No, it point to "xyz" regarding your code.
Que: what is size of s?
Ans: Its a bit tricky, "s" is the reference to "xyz". It is true for any declared variables which are referencing an object. So it is better to say, s is pointing to "xyz".
One important hint, memory of an object & referencing an object takes different memory space.
Immutable: A object is immutable if you cant change its property after instantiation.

Categories

Resources