I've read that in Java an object of type String can't change. But int and char variables can. Why is it? Can you give me an example?
Thank you.
(I am a newer -_- )
As bzabhi said, strings are immutable in Java. This means that a string object will never change. This does not mean you can not change string variables, just that you cannot change the underlying memory representation of the string. for an example:
String str = "Hello";
str += " World!";
Following the execution of these lines, str will point to a new string in memory. The original "Hello" string still exists in memory, but most likely it will not be there for long. Assuming that there are no extenuating circumstances, nothing will be pointing at the original string, so it will be garbage collected.
I guess the best way to put this would be to say that when line 2 of the example executes, a new string in memory is created from the concatenation of the original string and the string being added to it. The str variable, which is just a reference to a memory location, is then changed to point at the new variable that was just created.
I am not particularly knowledgeable on the point, but, as I understand it, this is what happens with all "non-primitive" values. Anything that at some point derives from Object follows these rules. Primitive values, such as ints, bools, chars, floats and doubles allow the actual value in memory to be changed. So, from this:
int num = 5;
num += 2;
the actual value in memory changes. Rather than creating a new object and changing the reference, this code sample will simply change the value in memory for the num variable.
As for why this is true, it is simply a design decision by the makers of Java. I'm sure someone will comment on why this was made, but that isn't something I know.
int and char can't change either. As with strings, you can put a different value into the same variable, but an integer itself doesn't change. 3 will always be 3; you can't modify it to be 4.
String is an immutable type (the value inside of it cannot change). The same is true for all primitive types (boolean, byte, char, short, int, long, float, and double).
int x;
String s;
x = 1;
x = 2;
s = "hello";
s = "world";
x++; // x = x + 1;
x--; // x = x - 1;
As you can see, in no case can you alter the constant value (1, 2, "hello", "world") but you can alter where they are pointing (if you warp your mind a bit and say that an int variable points at a constant int value).
I'm not sure that it is possible to show (by example) that Strings cannot change. But you can confirm this by reading the description section of Javadoc for the String class, then reading the methods section and noting that there are no methods that can change a String.
EDIT: There are many reasons why Strings are designed to be immutable in Java. The most important reason is that immutable Strings are easier to use correctly than mutable ones. And if you do need the mutable equivalent of a String for some reason, you can use the StringBuilder (or StringBuffer) class.
It's also worthwhile to note that since strings are immutable, that if they are passed into a method, they can't be modified inside of the method and then have those changes seen outside of the method scope.
public void changeIt(String s) {
// I can't do anything to s here that changes the value
// original string object passed into this method
}
public void changeIt(SomeObject o) {
// if SomeObject is mutable, I can do things to it that will
// be visible outside of this method call
}
This little article can probably explain it better than I can: http://www.jchq.net/tutorial/09_02Tut.htm
Strings are immutable in java. Nevertheless, you can still append or prepend values to strings. By values, I mean primitive data types or other strings.
However, a StringBuffer is mutable, i.e. it can be changed in memory (a new memory block doesn't have to be allocated), which makes it quite efficient. Also, consider the following example:
StringBuffer mystringbuffer = new StringBuffer(5000);
for (int i = 0; i<=1000; i++)
{
mystringbuffer.append ( 'Number ' + i + '\n');
}
System.out.print (mystringbuffer);
Rather than creating one thousand strings, we create a single object (mystringbuffer), which can expand in length. We can also set a recommended starting size (in this case, 5000 bytes), which means that the buffer doesn't have to be continually requesting memory when a new string is appended to it.
While a StringBuffer won't improve efficiency in every situation, if your application uses strings that grow in length, it would be efficient. Code can also be clearer with StringBuffers, because the append method saves you from having to use long assignment statements.
Related
See the code.
String xx=new String("hello world");
String yy="hello world";
System.out.println("xx: " + xx);
System.out.println("yy: " + yy);
System.out.println("xx==yy:"+(xx==yy)); // false
//modify the value of yy using reflection
Field yyfield=String.class.getDeclaredField("value");
yyfield.setAccessible(true);
char[] value=(char[])yyfield.get(yy); // change the value of yy
value[5]='_';
System.out.println("xx: " + xx); // xx's value also changed.why?
System.out.println("yy: " + yy);
System.out.println("xx==yy:"+(xx==yy)); //false
I've seen some posts about Literal Pool, know xx and yy point to different place. But why I change the value of yy, xx also changed. Is there any operation in reflection or some other aspects I don't know? Thanks in advance.
xx and yy are two distinct String instances but they refer to the same internal char[] array.
This is an implementation-specific detail and changed between the Java versions. In the past, the constructor String(String) offered a way to create a String with a new char[] array for the case that the source String is a sub-string of a much larger string. However, current implementations allocate a smaller array and copy contents in the subString operation already, eliminating the need for copying in the constructor, hence the constructor String(String) simply uses the same array reference.
Even more fancy, the most recent (Java 8) JVMs have a String de-duplication feature whereas the garbage collector will change the array references to point to the same array once it found out that two String instances have the same contents. So it can collect one of the two arrays while maintaining the same semantics.
The instance field value is the same instance for both xx and yy. This value also corresponds to the literal that's interned in the string pool.
So I was reading orcale java tutorials and I read
In this case, "Hello world!" is a string literal—a series of characters in your code that is enclosed in double quotes. Whenever it encounters a string literal in your code, the compiler creates a String object with its value
I want to make sure that am not creating random values all the time but this confused me, so does this mean that every time I use a string literal, a string object is created?
For example if I want to avoid creating new objects
String message = "am a NOT new string"
for(int i = 0; i < 1000; i++)
{
someStringarray[i] = message;
}
is more efficient than
for(int i = 0; i < 1000; i++)
{
someStringarray[i] = "am a new string EVERY time";
}
In Java, any instance of the same string literal always evaluates to the same object. In other words, in both of the above cases, there will only be one String object created, and the array will be filled in by having each entry reference that one string. There should not be an appreciable performance difference between the two.
Hope this helps!
"Whenever" is as seen by the compiler, not as seen by your program. The compiler sees the string "am a new string EVERY time" exactly once, when it compiles line 3 of your program. So there's only one copy of it.
In general, you know you're creating a new object because you use the new keyword (or you call a function which does).
All compile time string literals are interned(Java).
In the first case there is only one string in the memory and lots of pointers.
The second case is identical.
Wikipedia - String Interning
using it like you are at compile time the string table is created once at compile time and not repeated for each string, if you do create large arrays all pointing to the same object your are still using memory for the array itself. If you use StringBuffer type object or new() or take input from console then you would be using the heap and memory
I have 3 options:
Declare double member and later when I have to pass String use member + "".
Declare double member and later when I have to pass String use Double.toString(member).
Declare Double member = 0.0 and later when I have to pass String use member.toString().
My opinions:
The shortest one. However, member + "" will be converted to new StringBuilder().append(member).append("").toString(), which seems not elegant.
In Double.toString(member) I don't like that it doesn't start from the word member, which is the most important. We only need to convert it. It's better if member is in the beginning, because I pay most attention to the beginning of word. Quick glance and I know "ah, ok I'm passing member". And with Double.toString(member) my very first concentration goes to "ah, ok... a Double, we are doing toString... of a member! Ah ok".
member.toString() looks fine and it can be typed even faster then + "", because of autocompletion in Eclipse. However, objects are much slower then primitives. Reference.
What is the best option? Maybe there are some other options?
The best all-round approach, which will work for anything, is:
String s = String.valueOf(x);
Here x can be a primitive or an object, which (importantly) may be null.
Edit:
The hackaliciuos way is:
X + "";
Although note that this is not very efficient, because it compiles to:
new StringBuilder().append(x).append("").toString();
And the call to .append(x) invokes String.valueOf(x) anyway.
Note that arrays need special treatment:
String s = Arrays.toString(array);
I am having some difficulty in understanding how to write the below piece of code using String or char[] in Java.
void xyz(char *a, int startIndex, int endIndex)
{
int j;
for (j = startIndex; j <= endIndex; j++)
{
doThis((a+startIndex), (a+j));
xyz(a, startIndex+1, endIndex);
}
}
Here char *a points to the starting location of the char name[]
The above are just some random functions, but I just want the logic of how to use char* and character index char[] in Java
Based on the rephrased question from the comment thread:
You cannot change the characters of a Java String. If you need to modify a sequence of characters, use StringBuilder, which supports setCharAt(int, char), insert(int, char), and append(char). You can use new StringBuilder(myString) to convert a String to a StringBuilder, and stringBuilder.toString() to convert back.
This is perfectly legit Java code -- it's not code smelly, it's just the way you work with mutable character sequences.
A char* in C is, as you noted, pointing to the start of your character array (which is how C manages Strings).
In C the size of a char is one byte, and pointers always point to the start of a byte. Your C String is an array of characters, so adding 1 to a pointer moves the start of your string right by one character.
That means that the C code:
char *a;
// Set the String here
a = a + 1;
translates in Java to something like:
String a;
// Set the String here
a = a.substring(1);
or if you are using a char array:
char[] a;
// Set the array contents here
char[] copyTo = new char[a.length];
System.arraycopy(a, 1, copyTo, 0, a.length);
a = copyTo;
Java will be a bit more careful of protecting you that C will be though. For instance, if you have a zero length string, the C code has the potential to either segfault (crashing the application) or give you a gibberish string full of memory junk (then, eventually, crash the application), whereas the Java code will throw an exception (normally an IndexOutOfBoundsException) which you can, hopefully, handle cleanly.
Remember though, that String in Java are immutable. You cannot change them, you can only create new Strings. Fortunately, String has several built in functions which allow you to do a lot of the standard actions, like replace part of the String with another and return the result. A character array is mutable, and you can change the characters within them, but you will lose a lot of the nice benefits you get from using the proper String class.
Simple Answer:
You can't do exactly that. Java is pass by reference only. You don't have access to memory location information, so you can't do arithmetic with it.
Longer Answer:
It looks like you are passing in a string for manipulation. You have several options to simulate that.
You can convert the string to an array of characters and then pass in a char[]. If your manipulations are not any sort of standard string operation and completely custom this is probably what you need to do. Keep in mind that you can't change the size of the array passed in, nor can you have a point at a new array after the function completes. (again, only pass by value). Only the values of the existing elements of the array can be modified.
You can pass in the String and use the String methods, such as subString() (which your begin and end indexes seem to suggest, but this may not meet your needs. Note that strings are immutable however, and you can only get a result out via the return statement.
If you really need to modify the contents of the object passed in you can pass a StringBuilder, StringBuffer or CharBuffer object and modify away.
There's a hack that can also be used to circumvent pass by reference, but it's poor style except in special situations. Pass in an array of whatever you need to modify, so in this case an array of array of characters would allow you to set a new sub-array, and effectively acheive pass by reference, but try not to do this :)
If your method modifies the values you cant use String as that is immutable, you can use StringBuilder instead.
If your methods already rely on char arrays and you need the offsets you can use a CharBuffer to wrap an array. It does not support String operations but supports views for sub ranges, which seems to be what you use in the doThis() method.
public static void main(String [] a)
{
String s = new String("Hai");
String s1=s;
String s2="Hai";
String s3="Hai";
System.out.println(s.hashCode());
System.out.println(s1.hashCode());
System.out.println(s2.hashCode());
System.out.println(s3.hashCode());
System.out.println(s==s2);
System.out.println(s2==s3);
}
From the above code can anyone explain what is going behind when JVM encounters this line (s==s2) ?
It compares references - i.e. are both variables referring to the exact same object (rather than just equal ones).
s and s2 refer to different objects, so the expression evaluates to false.
s and s1 refer to the same objects (as each other) because of the assignment.
s2 and s3 refer to the same objects (as each other) because of string interning.
If that doesn't help much, please ask for more details on a particular bit. Objects and references can be confusing to start with.
Note that only string literals are interned by default... so even though s and s2 refer to equal strings, they're still two separate objects. Similarly if you write:
String x = new String("foo");
String y = new String("foo");
then x == y will evaluate to false. You can force interning, which in this case would actually return the interned literal:
String x = new String("foo");
String y = new String("foo");
String z = "foo";
// Expressions and their values:
x == y: false
x == z: false
x.intern() == y.intern(): true
x.intern() == z: true
EDIT: A comment suggested that new String(String) is basically pointless. This isn't the case, in fact.
A String refers to a char[], with an offset and a length. If you take a substring, it will create a new String referring to the same char[], just with a different offset and length. If you need to keep a small substring of a long string for a long time, but the long string itself isn't needed, then it's useful to use the new String(String) constructor to create a copy of just the piece you need, allowing the larger char[] to be garbage collected.
An example of this is reading a dictionary file - lots of short words, one per line. If you use BufferedReader.readLine(), the allocated char array will be at least 80 chars (in the standard JDK, anyway). That means that even a short word like "and" takes a char array of 160 bytes + overheads... you can run out of space pretty quickly that way. Using new String(reader.readLine()) can save the day.
== compars objects not the content of an object. s and s2 are different objects. If you want to compare the content use s.equals(s2).
Think of it like this.
Identical twins look the same but they are made up differently.
If you want to know if they "look" the same use the compare.
If you want to know they are a clone of each other use the "=="
:)
== compares the memory (reference) location of the Objects. You should use .equals() to compare the contents of the object.
You can use == for ints and doubles because they are primitive data types
I suppose you know that when you test equality between variables using '==', you are in fact testing if the references in memory are the same. This is different from the equals() method that combines an algorithm and attributes to return a result stating that two Objects are considered as being the same. In this case, if the result is true, it normally means that both references are pointing to the same Object. This leaves me wondering why s2==s3 returns true and whether String instances (which are immutable) are pooled for reuse somewhere.
It should be an obvious false. JVM does a thing like using the strings that exist in the Memory . Hence s2,s3 point to the same String that has been instantiated once. If you do something like s5="Hai" even that will be equal to s3.
However new creates a new Object. Irrespective if the String is already exisitng or not. Hence s doesnot equal to s3,s4.
Now if you do s6= new String("Hai"), even that will not be equal to s2,s3 or s.
The literals s2 and s3 will point to the same string in memory as they are present at compile time. s is created at runtime and will point to a different instance of "Hai" in memory. If you want s to point to the same instance of "Hai" as s2 and s3 you can ask Java to do that for you by calling intern. So s.intern == s2 will be true.
Good article here.
You are using some '==' overload for String class...