Strings...immutable?

P

printdude1968

I read in a book that String objects are immutable, yet a few lines
later they show some code in which a String object is added to by
using the '+' operation. I must be misunderstanding what is meant by
immutable becuase it seems to me that

String s = 'hello';
s += 'good-bye';

should result in a compiler error if in fact the string is
immuatable. Can anyone clarify this for me?
 
J

Jeff Higgins

I read in a book that String objects are immutable, yet a few lines
later they show some code in which a String object is added to by
using the '+' operation. I must be misunderstanding what is meant by
immutable becuase it seems to me that

String s = 'hello';
s += 'good-bye';

should result in a compiler error if in fact the string is
immuatable. Can anyone clarify this for me?
http://mindprod.com/jgloss/interned.html
 
P

Patricia Shanahan

I read in a book that String objects are immutable, yet a few lines
later they show some code in which a String object is added to by
using the '+' operation. I must be misunderstanding what is meant by
immutable becuase it seems to me that

String s = 'hello';
s += 'good-bye';

should result in a compiler error if in fact the string is
immuatable. Can anyone clarify this for me?

s is not a String object, it is a reference variable that can either be
null or point to a String object.

The += changes s from pointing to the "hello" String object to instead
point to a String object with value "hello"+"good-bye". It does not
change the "hello" object.

You can test it with this program:

public class Concatenate {
public static void main(String[] args) {
String s = "hello";
String x = s;
s += "good-bye";
System.out.println(x);
}
}

which shows that "hello" is unaffected by the +=.

Patricia
 
J

Jeff Higgins

I read in a book that String objects are immutable, yet a few lines
later they show some code in which a String object is added to by
using the '+' operation. I must be misunderstanding what is meant by
immutable becuase it seems to me that

String s = 'hello';
s += 'good-bye';

should result in a compiler error if in fact the string is
immuatable. Can anyone clarify this for me?
http://mindprod.com/jgloss/string.html
 
M

Mark Space

Patricia said:
(e-mail address removed) wrote:
s is not a String object, it is a reference variable that can either be
null or point to a String object.

The += changes s from pointing to the "hello" String object to instead
point to a String object with value "hello"+"good-bye". It does not
change the "hello" object.

String s = "hello";
String x = s;
s += "good-bye";

Yup. To clarify just a bit more, in your original example, the original
object "hello" is tossed away. There's no reference to it, so it's just
left on the heap, and it'll be garbage-collect later. In Patricia's
example, there's a reference to "hello" retained in x, so this time the
"hello" object will stick around, and it's usable later, like for
printing out.
 
P

Phi

Have a look at the following code


String s = " hallo "; // notice the blanks before and after the word
"hello"
s.trim(); // expect that the spaces disapear?

The string represented by the referece "s" is not changed (that means
immutable).

But most String-Mehtods return a new object containing the expeced result.

String s1, s2;
s1 = " hallo ";
s2 = s1.trim();

Or shorter

String s = " hello ";
s = s.trim();

Now you could say that s has changed! This is true, the reference "s"
now points to the result of the trim() Method, which is a new object!
The old object " hello " still remains in memory, but is no longer
pointed to by "s". This makes you think, the string has changed.
This is not true! Only the reference s points to a new object.

greets

phi
 
M

Mark Thornton

Mark said:
Yup. To clarify just a bit more, in your original example, the original
object "hello" is tossed away. There's no reference to it, so it's just
left on the heap, and it'll be garbage-collect later.

Actually it won't get garbage collected unless the class is also garbage
collected. There is, in effect, a hidden reference from the class to all
literal Strings declared in it.

Mark Thornton
 
M

Mark Space

Mark said:
Actually it won't get garbage collected unless the class is also garbage
collected. There is, in effect, a hidden reference from the class to all
literal Strings declared in it.

I don't believe this.

First it doesn't make any sense from a design view-point. And second
where is one class gonna keep references to 1000 or more odd unused strings?

Where did you hear this?
 
B

Bent C Dalager

I don't believe this.

First it doesn't make any sense from a design view-point. And second
where is one class gonna keep references to 1000 or more odd unused strings?

I wouldn't expect many classes to have thousands of string literals in
them.

From a design viewpoint, keeping the string literals around as cached
String objects makes sense since you can just reuse those objects
every time a new instance of the class is created.

Cheers
Bent D
 
J

jupiter

Mark Thornton said:
Actually it won't get garbage collected unless the class is also
garbage collected. There is, in effect, a hidden reference from
the class to all literal Strings declared in it.

Mark Thornton

Wowza-roni!

Are you sure about that? I think this one slipped past some of the
big brains who have written some very good books on the subject.

Nice catch. If that's true then it might indicate why profilers
are showing kabillions of String objects that supposedly should not
be there any more. Oh well, I guess if you never ran out of heap
in an inglorious crash you wouldn't care about this.
 
J

jupiter

I read in a book that String objects are immutable, yet a few
lines
later they show some code in which a String object is added to by
using the '+' operation. I must be misunderstanding what is
meant by
immutable becuase it seems to me that

String s = 'hello';
s += 'good-bye';

should result in a compiler error if in fact the string is
immuatable. Can anyone clarify this for me?

Heap and stack are two different memory storage spaces. One is
for Object and one is for references to Object.

It helped me to "see" in my mind that a String is put on the heap
as an Object, while references remain only on the stack pointing to
the Object address.

So, s starts out being a reference and remains a reference. When
it points to "hello" it points to the "hello" Object on the heap.
When s points to "hellogoodbye" it's pointing to a new heap Object.
So they are different objects, and nothing has been mutated.

I think that's right. Is that right? I think somebody will
correct me if not.
 
J

Joshua Cranmer

jupiter said:
Heap and stack are two different memory storage spaces. One is
for Object and one is for references to Object.

It helped me to "see" in my mind that a String is put on the heap
as an Object, while references remain only on the stack pointing to
the Object address.

So, s starts out being a reference and remains a reference. When
it points to "hello" it points to the "hello" Object on the heap.
When s points to "hellogoodbye" it's pointing to a new heap Object.
So they are different objects, and nothing has been mutated.

I think that's right. Is that right? I think somebody will
correct me if not.

The memory management in the JVM is much more complicated than that (I
don't know much about, so anyone correct me if I get something wrong).
There is the basic stack frame (per thread?), which stores all of the
local variables, Object references, etc. Then there is the heap space,
which stores the actual objects. There is also a separate space for the
class references and internal String references -- String's interns are
NOT stored in the heap.

So, the "hello" object has a pointer on the stack frame, a reference to
the String variable in the heap, a reference to the class AND the
interned String in the other memory space.

As two asides:
1. a java.lang.OutOfMemoryError: heap space cannot be due to having too
many String interns, it can only be due to using too much data.
2. This should return true, using the Sun JVM:

public class Foo {
final static String bar1 = "Hello";
final static String bar2 = "Hello";

public static boolean equal() {
return bar1 == bar2;
}
}
 
L

Lew

Mark said:
I don't believe this.

It's true.
First it doesn't make any sense from a design view-point. And second
where is one class gonna keep references to 1000 or more odd unused
strings?

In its "pool of strings, initially empty, ... maintained privately by the
class String."

The number of such strings is determined by the number of literal strings in
your program. Such strings could be in ROM, theoretically.
Where did you hear this?

From the JLS.
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.

It didn't.

Mostly the interned strings are computed at compile time, so there is no
impact on dynamic memory usage. If you explicitly use the String.intern() method
<http://java.sun.com/javase/6/docs/api/java/lang/String.html#intern()>
then the canonical representation of the string will be in a "pool of strings,
initially empty, ... maintained privately by the class String."

Since there are negligibly few situations where one calls intern() explicitly,
and presumably then only for frequently reused values, this mechanism was
never responsible for when "you ... ran out of heap in an inglorious crash".

-- Lew
 
L

Lew

Joshua said:
2. This should return true, using the Sun JVM:

public class Foo {
final static String bar1 = "Hello";
final static String bar2 = "Hello";

public static boolean equal() {
return bar1 == bar2;
}
}

It must return true, given anyone's JVM.
* Literal strings within the same class (§8) in the same package (§7) represent references to the same String object (§4.3.1).
* Literal strings within different classes in the same package represent references to the same String object.
* Literal strings within different classes in different packages likewise represent references to the same String object.
* Strings computed by constant expressions (§15.28) are computed at compile time and then treated as if they were literals.
* Strings computed by concatenation at run time are newly created and therefore distinct.

-- Lew
 
C

Chris Uppal

Mark said:
I don't believe this.

First it doesn't make any sense from a design view-point. And second
where is one class gonna keep references to 1000 or more odd unused
strings?

It is, however, true.

I wouldn't have phrased it quite as Mark Thornton did, but I'm sure he meant
the same as I would have done if I had (if you see what I mean ;-)

The essential points are that the JLS requires that string literals are treated
specially in various ways. One of them is that if the same (character by
character) string literals occurs more than once anywhere in the Java source,
then there must be a /single/ String object which is the value of /all/ of
those expressions. There is some extra stuff to tie that fundamental
requirement together with the String interning stuff -- it is required that for
any String which is the value of a string literal:

someString = "whatever; // a string literal expression
someString == someString.intern();

someString = "whatever" + " " + "else"; // another string literal
expression
someString == someString.intern();

At the implementation level (below the level visible from Java, or even JNI),
this is connected with the "constant pool" in each .CLASS file. That holds a
good deal of information; notably, the values of all non-trivial literals in
the source, including the values of all string literals.

-- chris
 
M

Mike Schilling

Mark said:
Actually it won't get garbage collected unless the class is also
garbage collected. There is, in effect, a hidden reference from the
class to all literal Strings declared in it.

Do you have a reference for that?

My understanding is that string literals live in the pool of interned
Strings, which is JVM-wide. When a class that contains a "hello" literal is
loaded, during its initialization it looks for "hello" in the interned
strings, and creates it only if it's not already present. Since the
interned strings aren't collected for the life of the JVM. There's no need
for the class to maintain a reference to it. And as a result, "hello" won't
be collected even if all of the classes which reference it are collected.
 
M

Mark Thornton

Mike said:
Do you have a reference for that?

My understanding is that string literals live in the pool of interned
Strings, which is JVM-wide. When a class that contains a "hello" literal is
loaded, during its initialization it looks for "hello" in the interned
strings, and creates it only if it's not already present. Since the
interned strings aren't collected for the life of the JVM. There's no need
for the class to maintain a reference to it. And as a result, "hello" won't
be collected even if all of the classes which reference it are collected.

That used to be true, but the implementation of interning was modified
to use WeakReference.

http://mindprod.com/jgloss/interned.html

http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4035345

Fixed in 1.2beta.

Mark Thornton
 
M

Mark Thornton

Chris said:
Mark Space wrote:




It is, however, true.

I wouldn't have phrased it quite as Mark Thornton did, but I'm sure he meant
the same as I would have done if I had (if you see what I mean ;-)

Your explanation is much longer than mine! :)

Mark Thornton
 
P

Patricia Shanahan

Mark said:
Yup. To clarify just a bit more, in your original example, the original
object "hello" is tossed away. There's no reference to it, so it's just
left on the heap, and it'll be garbage-collect later. In Patricia's
example, there's a reference to "hello" retained in x, so this time the
"hello" object will stick around, and it's usable later, like for
printing out.

I didn't mention what would happen to "hello" because I thought it would
bring up the intern issue, and be more confusing than enlightening.

After watching this thread for a bit, I think I was right.

Patricia
 
M

Mark Thornton

Patricia said:
After watching this thread for a bit, I think I was right.

;-) and we haven't got to the question of when do classes get garbage
collected yet (or which version of Java changed this behaviour)!

Mark
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,050
Latest member
AngelS122

Latest Threads

Top