Can you change a String object after you create it? - java

If you answer "yes", then give an example of how you can change a String.
If you answer "no", then explain why the Java designers don't let us modify Strings

No.
Strings are immutable by design. If you want to alter a string, I suggest you look at the StringBuffer class.
Immutable is a design pattern. As multiple entities can reference an object, immutability ensures that the object you reference has not been altered by some other object that references it.

No, you cannot modify a string after you create it. String is an example of an immutable class. If you have the following code:
String a = "hello";
String b = a;
a and b are now referencing the same object, but there is nothing that you can do to a that will change the string that b is referencing. You can only assign a to a different string.
I can only speculate about why the Java designers chose to have it this way, but I suspect a major reason is to facilitate code predictability. If you had something like this.
String h = "house";
String hcopy = h;
and at some later point you were able to modify h in some way like h.splitInHalf() that actually changed h's string, that would also affect hcopy and make things very frustrating when simple String variables changed values without warning.
If you would like a String-like structure that you can modify, you can use StringBuffer.

You can't not,each time you try to change it,a new String object is actually created.If you want to use changable String,use StringBuffer,StringBuilder instead.
There is a String constant pool in memory for better performence.

In my experience, that's a popular interview question. The objective is to figure out whether the interviewee knows the internals of the java.lang.String class.
So to answer the question, by design, Java does not allow to change a String object, those objects are immutable. However, though you should never do it in a real production code, it is technically possible to change a String object using the Reflection API.
import java.lang.reflect.Field;
public class App {
public static void main(String[] args) throws Exception {
String str = "Hello world!";
Field valueField = String.class.getDeclaredField("value");
valueField.setAccessible(true);
char[] c = (char[]) valueField.get(str);
c[1] = 'a';
System.out.println(str); //prints Hallo world!
}
}
As is often said, Java will let you shoot yourself in the foot after you use a magic spell of "import java.lang.reflect.*;"

Related

static final String = "something" -- does the static make sense?

static final String = "something";
I was wondering if such a declaration has some kind real sense in Java. I've found it thousands of time within the code but studying and playing with strings I've learnt that does not matter how many times you declare a String object: if some class before yours declared this string this is pooled and reused (I'm talking about String created without explicit constructor invocation)
public class StringCompare {
private void toCompare(String h) {
String x = "hello";
System.out.println( x == h);
}
public void compare() {
String h = "hello";
toCompare(h);
}
}
This code, in fact, prints true when calling compare so the 2 variables are referencing the same object. Said that a final variable can't be redefined, the static word is completely useless in this case. Am I missing the point?
Couple of more things:
1 - Why explicit call to String constructor won't cause the String to be pooled? Same code above using a new String("hello") print false.
2 - Is the pooling behaviour reserved to Strings? There are some other immutable objects (like BigInteger) but I think these are not pooled ... why?
Thanks,
Carlo
There are a few reasons why developers use this pattern, even though your analysis of the runtime behavior and its use the string pool is correct.
It communicates the developers intent more cleanly. Specifically the string now has a name that is hopefully more clear than the constant, and it communicates the runtime behaviour that not everybody is aware of (or they forget from time to time).
If the developer wants to change the value within the source file, and it has been used in multiple places then there is only one place to make that change.
Once the decision to use a variable has been made, the keyword static will mean that the memory usage is lower. That is, there is only one field used to store the ref rather than one field per instance of the object.
As for your follow on questions:
Q: Why explicit call to String constructor won't cause the String to be pooled? Same code above using a new String("hello") print false.
Because the string pool is only used for string literals, as described by the JLS and invoking a constructor is not classified as a string literal.
Q: Is the pooling behaviour reserved to Strings?
The string pool is only used for string literals, but there is of course other caches for different use cases. The most obvious one that jumps to mind is the int cache used to optimize auto boxing of ints.
Even if the static doesn't give you a memory benefit in this case, you can still access the field in a static way, so you don't need an instance. For example, you frequently use some URIs, so you create the following class:
public class Uris
{
public static final String GOOGLE = "http://google.com";
public static final String BBC = "http://bbc.co.uk";
}
Using static, you can just use Uris.GOOGLE instead of new Uris().GOOGLE.
The static means that for each new object created for that class, the String construction & pooling only has to happen once, ever. This is a small saving in computation.
it is because String ="hello" or String h are not creating any object in heap these all are stored inString constant pool where as new String("hello"); create a new object in heap and so address will be different
check details here
String x = "hello";
String h = "hello";
are two String literals. They are in common pool(part of String pool). There are referring same reference. Then == check the reference you will get true
If you use String x = new String("hello"), it will create a new String object x. of course referring new reference. Now compare reference give you false.

rely on java String copy on write

My application creates a lot of instances of a class, say class A. All instance contains a string, and most of them contain the same String
class A {
String myString;
}
I know that JVM makes "all equal strings" point to the same String that is stored just one time. If myString field of one of my A instances is overwritten, the reference to the original string is replaced by the reference to the new String value and all works as expected, that is as if each instance had a copy of the string all for itself.
Is this behaviour required to a compliant JVM, or is it a sort of improvement of the jvm that may change from a jvm to another, or from version to version?
Another way to put the question: when designing higly redundant (string based) data-structures, should one rely only on the copy on write mechanism or it is adviceable to put in place something at the application level?
Another aspect of this is that your Strings will not be the same if they are created dynamically (e.g. allocated by parser). Check out String.intern() if space is a concern:
String a = String.valueOf('a') + "b";
String b = a.intern();
String c = "ab";
// now b == c is true
as #Hot Licks said: strings are immutable so there is no place to talk about copy on write. also when you are using mutable object you have to be aware that 'copy on write' may not be available on your client's environment.
and another thing that may be very important when you create a lot of objects. each object contains a few bytes of header, pointers etc. if i remember correctly empty object is like 20 bytes or so. when you we are talking about a lot of objects containing properties it starts to be significant. be aware of that and when you measure that it is causing the problem then you have to do something at the application level (lightweight design pattern, using stream xml parser etc).
The fact is that String are regular objects.
String a = "test";
String b = a;
Does exactly the same thing as:
StringBuffer a = new StringBuffer("test");
StringBuffer b = a;
that is: in both cases, b is a second reference to a, and this is not due to the immutability.
Immutability comes into play
So, you always handle two pointers to the same data. Now, if the class is immutable, you can forget about it: nobody will change your data under your shoes not because you have a copy for your own, but because the shared copy is immutable. You can even think that you have a copy of the string, but actually a copy has never existed since String b = a; does what it does for each object: a copy of the only reference.

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

effect of changing String using reflection

As we all know, String is immutable in java. however, one can change it using reflection, by getting the Field and setting access level. (I know it is unadvised, I am not planning to do so, this question is pure theoretical).
my question: assuming I know what I am doing (and modify all fields as needed), will the program run properly? or does the jvm makes some optimizations that rely on String being immutable? will I suffer performance loss? if so, what assumption does it make? what will go wrong in the program
p.s. String is just an example, I am interested actually in a general answer, in addition to the example.
thanks!
After compilation some strings may refer to the one instance, so, you will edit more than you want and never know what else are you editing.
public static void main(String args[]) throws Exception {
String s1 = "Hello"; // I want to edit it
String s2 = "Hello"; // It may be anywhere and must not be edited
Field f = String.class.getDeclaredField("value");
f.setAccessible(true);
f.set(s1, "Doesn't say hello".toCharArray());
System.out.println(s2);
}
Output:
Doesn't say hello
You are definitely asking for trouble if you do this. Does that mean you will definitely see bugs right away? No. You might get away with it in a lot of cases, depending on what you're doing.
Here are a couple of cases where it would bite you:
You modify a string that happens to have been declared as literal somewhere within the code. For example you have a function and somewhere it is being called like function("Bob"); in this scenario the string "Bob" is changed throughout your app (this will also be true of string constants declared as final).
You modify a string which is used in substring operations, or which is the result of a substring operation. In Java, taking a substring of a string actually uses the same underlying character array as the source string, which means modifications to the source string will affect substrings (and vice versa).
You modify a string that happens to be used as a key in a map somewhere. It will no longer compare equal to its original value, so lookups will fail.
I know this question is about Java, but I wrote a blog post a while back illustrating just how insane your program may behave if you mutate a string in .NET. The situations are really quite similar.
The thing that jumps to mind for me is string interning - literals, anything in the constant pool and anything manually intern()ed points to the same string object. If you start messing around with the contents of an interned string literal, you may well see the exact same alterations on all the other literals using the same underlying object.
I'm not sure whether the above actually happens since I've never tried (in theory it will, I don't know if something happens under the scene to stop it but I doubt it) but it's things like that that could throw up potential problems. Of course, it could also throw up problems at the Java level through just passing multiple references to the same string around and then using a reflection attack to alter the object from one of the references. Most people (me included!) won't explicitly guard against that sort of thing in code, so using that attack with any code that's not your own, or your own code if you haven't guarded against that either, could cause all sorts of bizarre, horrible bugs.
It's an interesting area theoretically, but the more you dig around the more you see why anything along these lines is a bad idea!
Speaking outside of string, there's no performance enhancements I know of for an object being immutable (indeed I don't think the JVM can even tell at the moment whether an object is immutable, reflection attacks aside.) It could throw things like the checker-framework off though or anything that tries to statically analyse the code to guarantee it's immutable.
I'm pretty sure The JVM itself makes no assumptions about the immutability of Strings, as "immutability" in Java is not a language-level construct; it's a trait implied by a class's implementation, but cannot, as you note, be actually guaranteed in the presence of reflection. Thus, it also shouldn't be relevant to performance.
However, pretty much all Java code in existence (including the Standard API implementation) relies on Strings being immutable, and if you break that expectation, you'll see all kinds of bugs.
The private fields in the String class are the char[], the offset and length. Changing any of these should not have any adverse effect on any other object. But if you can somehow change the contents of the char[], then you could probably see some surprising side effects.
public static void main(String args[]){
String a = "test213";
String s = new String("test213");
try {
System.out.println(s);
System.out.println(a);
char[] value = (char[])getFieldValue(s, "value");
value[1] = 'a';
System.out.println(s);
System.out.println(a);
} catch (Exception e) {
e.printStackTrace();
}
}
static Object getFieldValue(String s,String fieldName) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
Object chars = null;
Field innerCharArray = String.class.getDeclaredField(fieldName);
innerCharArray.setAccessible(true);
chars = innerCharArray.get(s);
return chars;
}
Changing value of S will change the literal of a as mentioned in all answers.
To demonstrate how can it screw up a program:
System.out.print("Initial: "); System.out.println(addr);
editIntStr("ADDR_PLACEH", "192.168.1.1");
System.out.print("From var: "); System.out.println(addr);//
System.out.print("Hardcoded: "); System.out.println("ADDR_PLACEH");
System.out.print("Substring: "); System.out.println("ADDR_PLACE" + "H".substring(0));
System.out.print("Equals test: "); System.out.println("ADDR_PLACEH".equals("192.168.1.1"));
System.out.print("Equals test with substring: "); System.out.println(("ADDR_PLACE" + "H".substring(0)).equals("192.168.1.1"));
Output:
Initial: ADDR_PLACEH
From var: 192.168.1.1
Hardcoded: 192.168.1.1
Substring: ADDR_PLACEH
Equals test: true
Equals test with substring: false
The result of the first Equals test is weird, isn't it? You can't expect your fellow programmers to figure out why is Java thinking they are equal...
Full test code: http://pastebin.com/vbstfWX1

What is the purpose of modifying a string using reflection?

I was reading an article that said that Java strings are not completely immutable. However, in the article's sample code that modifies the string, it makes a call to string.toUpperCase().toCharArray(), which returns a new string. So what's the purpose of going through the process of changing the string if you call toUpperCase() anyway? Here is the code:
public static void toUpperCase(String orig)
{
try
{
Field stringValue = String.class.getDeclaredField("value");
stringValue.setAccessible(true);
stringValue.set(orig, orig.toUpperCase().toCharArray());
}
catch (Exception ex){}
}
Also, I noticed that string.toUpperCase() by itself doesn't work. It needs to be string.toUpperCase().toCharArray(). Is there a reason for this?
What he's doing:
He's acquring some character array that he knows is the right length (such as the uppercase version of the String) and putting it as the backing array of the String. (The backing array is called value inside the String class.)
Why he's doing it:
To illustrate that you could put any char array there you wanted.
Why this is useful:
String is immutable, and this allows you to circumvent the immutability. Of course, this is not recommended to do - EVER. On the contrary, I would not be surprised if he was saying "Watch out, because people could potentially do this to YOUR code. Even if you think your stuff is safe, it might not be!"
The implications of this are wide reaching. Immutable variables are no longer immutable. Final variables are no longer final. Thread safe objects are no longer thread safe. Contracts you thought you could rely upon, you can no longer do so. All because some engineer somewhere had a problem he couldn't fix with normal means, so he delves into reflection to solve it. Don't be 'that guy'.
You'll also note that how the hashCode for that String would now be changed. So, if you've never calculated the hashCode for that String, it's still 0 so you're okay. On the other hand, if you have calculated it, when you go to put it in a HashMap or HashSet, it won't be retrieved.
Consider the following:
import java.util.*;
import java.lang.reflect.*;
class HashTest {
/** Results:
C:\Documents and Settings\glowcoder\My Documents>java HashTest
Orig hash: -804322678
New value: STACKOVERFLOW
Contains orig: true
Contains copy: false
*/
public static void main(String[] args) throws Exception {
Set<String> set = new HashSet<String>();
String str = "StackOverflow";
System.out.println("Orig hash: " + str.hashCode());
set.add(str);
Field stringValue = String.class.getDeclaredField("value");
stringValue.setAccessible(true);
stringValue.set(str, str.toUpperCase().toCharArray()); //
System.out.println("New value: " + str);
String copy = new String(str); // force a copy
System.out.println("Contains orig: " + set.contains(str));
System.out.println("Contains copy: " + set.contains(copy));
}
}
I would bet he is doing this as a warning against bad behavior rather than showing a 'cool' trick.
EDIT: I found the article you're referring to, and the article it is based on. The original article states: "This means that if a class in another package "fiddles" with an interned String, it can cause havoc in your program. Is this a good thing? (You don't need to answer ;-) " I think that makes it quite clear this is more of a protection guide than advice on how to code.
So if you walk away from this thread with only one piece of information, it is that reflection is dangerous, unreliable, and not to be trifled with!
Don't try this at home!
You are subverting String's immutability. There is no good reason to do this.
I think I cannot add to the explanations already provided, so perhaps I can add to the discussion by suggesting how this can be prevented.
You can prevent somebody tampering with your code in these and other unintended ways by means of using a security manager.
public static void main(String args[]){
System.setSecurityManager(new SecurityManager());
String jedi1 = "jedi";
toUpperCase(jedi1);
System.out.println(jedi1);
}
This will generate an exception in the toUpperCase method, provided that you are not granting all privileges to all code bases in the default policy files. (In your current code your exceptions are currently swallowed).
What is the purpose? I'm not sure, ask the one that wrote this stuff. You normally should not do something like this. There is a reason String is immutable.
Here how this method would look if the fields were public, i.e. without reflection:
public static void toUpperCase(String orig) {
orig.value = orig.toUpperCase().toCharArray();
}
As value is of type char[], you can't assign a String to this field - this is why you need the toCharArray call after .toUpperCase(). You will get an exception if you try to do this (I suppose ClassCastException), but the try-catch block there eats it away. (This gets us another lesson: Never use such empty catch blocks.)
Pay attention: This code might not do the correct thing, since the actual data of the original string might not start at the start of the char[]. Since you don't update the offset field, you will get IndexOutOfBoundsExceptions when using such a modified String. Also, the String object caches its hashCode, thus this will be wrong, too.
Here would be a correct way:
public static void toUpperCase(String orig) {
orig.value = orig.toUpperCase().toCharArray();
orig.offset = 0;
orig.hash = 0; // will be recalculated on next `.hashCode()` call.
}
With reflection, it looks like this:
public static void toUpperCase(String orig)
{
try
{
Field stringValue = String.class.getDeclaredField("value");
stringValue.setAccessible(true);
stringValue.set(orig, orig.toUpperCase().toCharArray());
Field stringOffset = String.class.getDeclaredField("offset");
stringOffset.setAccessible(true);
stringOffset.setInt(orig, 0);
Field stringHash = String.class.getDeclaredField("hash");
stringHash.setAccessible(true);
stringHash.setInt(orig, 0);
}
catch (Exception ex){
// at least print the output
ex.printStackTrace();
}
}
1.) Read Bohemian answer.
2.) Strings are internally stored in a char array, that's why you need to call toCharArray to set the field.
By default, String.toUpperCase() leaves the original string intact, whilst returning a new string object.
The function you defined above, edits the contents of the original string object in-place.
You change a final string with reflection for testing. Sometimes that string contains the path to a default location used in the production environment but not suitable for testing. Yet, that variable is referenced by several objects/methods your trigger in your test, and hence during your tests you might want to set it to a particular value.
As others said, it's probably something you don't want to be doing (often/ever).

Categories

Resources