15

This Java tutorial says that an immutable object cannot change its state after creation.

java.lang.String has a field

/** Cache the hash code for the string */
private int hash; // Default to 0

which is initialized on the first call of the hashCode() method, so it changes after creation:

    String s = new String(new char[] {' '});
    Field hash = s.getClass().getDeclaredField("hash");
    hash.setAccessible(true);
    System.out.println(hash.get(s));
    s.hashCode();
    System.out.println(hash.get(s));

output

0
32

Is it correct to call String immutable?

Sled
  • 18,541
  • 27
  • 119
  • 168
Evgeniy Dorofeev
  • 133,369
  • 30
  • 199
  • 275

9 Answers9

13

A better definition would be not that the object does not change, but that it cannot be observed to have been changed. It's behavior will never change: .substring(x,y) will always return the same thing for that string ditto for equals and all the other methods.

That variable is calculated the first time you call .hashcode() and is cached for further calls. This is basically what they call "memoization" in functional programming languages.

Reflection isn't really a tool for "programming" but rather for meta-programming (ie programming programs for generating programs) so it doesn't really count. It's the equivalent of changing a constant's value using a memory debugger.

Sled
  • 18,541
  • 27
  • 119
  • 168
8

The term "Immutable" is vague enough to not allow for a precise definition.

I suggest reading Kinds of Immutability from Eric Lippert's blog. Although it's technically a C# article, it's quite relevant to the question posed. In particular:

Observational immutability:

Suppose you’ve got an object which has the property that every time you call a method on it, look at a field, etc, you get the same result. From the point of view of the caller such an object would be immutable. However you could imagine that behind the scenes the object was doing lazy initialization, memoizing results of function calls in a hash table, etc. The “guts” of the object might be entirely mutable.

What does it matter? Truly deeply immutable objects never change their internal state at all, and are therefore inherently threadsafe. An object which is mutable behind the scenes might still need to have complicated threading code in order to protect its internal mutable state from corruption should the object be called on two threads “at the same time”.

Ani
  • 111,048
  • 26
  • 262
  • 307
  • I guess unless you are being absolute the question of "immutability" depends on from whose (i.e. which object's) perspective it's being asked. – Sled Mar 11 '13 at 17:04
3

Once created, all the methods on a String instance (called with the same parameters) will always provide the same result. You cannot change its behavoiur (with any public method), so it will always represent the same entity. Also it is final and cannot be subclassed, so it is guaranteed that all instances will behave like this.

Therefore from public view the object is considered immutable. The internal state does not really matter in this case.

gaborsch
  • 15,408
  • 6
  • 37
  • 48
  • Ah yes, but in this case he is using devious tricks to change the `hash` variable, and the `hash` variable is observable via `hashcode()`. So by your definition, String would be mutable. – Stephen C Mar 07 '13 at 16:00
  • I didn't repeat the first comment that *reflection does not count* even in my definition. – gaborsch Mar 07 '13 at 16:03
1

Yes it is correct to call them immutable.

While it is true that you can reach in and modify private ... and final ... variables of a class, it is an unnecessary and incredibly unwise thing to do on a String object. It is generally assumed that nobody is going to be crazy enough do it.

From a security standpoint, the reflection calls needed to modify the state of a String all perform security checks. Unless you've miss-implement your sandbox, the calls will be blocked for non-trusted code. So you should have to worry about this as a way that untrusted code can break sandbox security.

It is also worth noting that the JLS states that using reflection to change final, may break things (e.g. in multi-threading) or may not have any effect.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
  • I used the public method hashCode() to change the hash field. Docs says that immutable objects cannot their state after creation. Is the hash field part of a String instance state or not? – Evgeniy Dorofeev Mar 07 '13 at 16:03
  • @EvgeniyDorofeev: With a few exceptions (such as `delay` methods), the fact that a method takes time to execute is not considered to be part of its behavior. The only observable difference between a `string` object whose hash field is zero, and one whose hash field isn't, will be the amount of time required to execute its `hashCode()` method. Note that if the computed hash value depended in some way upon when the first call to `hashCode()` was performed, that *would* represent mutable state, but it doesn't. – supercat Jul 11 '13 at 21:41
  • @EvgeniyDorofeev - In the case you are talking about (`String`), the answer depends on your perspective. See Ani's answer. Also remember that the Java Tutorial is not the specification. It is a simplified version of information in (more) definitive documents. If you look at the JLS, *immutability* is not a core property. Rather it is a property of a class that emerges from the way that the classes API design and its implementation. The prime purpose of the Java Tutorial is to help beginners ... not to be a definitive text. – Stephen C Jul 11 '13 at 22:46
1

From the viewpoint of a developer who is using reflection, it is not correct to call String immutable. There are actual Java developers using reflection to write real software every day. Dismissing reflection as a "hack" is preposterous. However, from the viewpoint of a developer who is not using reflection, it is correct to call String immutable. Whether or not it is valid to assume that String is immutable depends on context.

Immutability is an abstract concept and therefore cannot apply in an absolute sense to anything with a physical form (see the ship of Theseus). Programming language constructs like objects, variables, and methods exist physically as bits in a storage medium. Data degradation is a physical process which happens to all storage media, so no data can ever be said to be truly immutable. In addition, it is almost always possible in practice to subvert the programming language features intended to prevent the mutation of a particular datum. In contrast, the number 3 is 3, has always been 3, and will always be 3.

As applied to program data, immutability should be considered a useful assumption rather than a fundamental property. For example, if one assumes that a String is immutable, one may cache its hash code for reuse and avoid the cost of ever recomputing its hash code again later. Virtually all non-trivial software relies on assumptions that certain data will not mutate for certain durations of time. Software developers generally assume that the code segment of a program will not change while it is executing, unless they are writing self-modifying code. Understanding what assumptions are valid in a particular context is an important aspect of software development.

Mark
  • 3,057
  • 1
  • 14
  • 5
0

It can not be modified from outside and it is a final class, so it can not be subclassed and made mutable. Theese are two requirments for immutability. Reflection is considered as a hack, its not a normal way of development.

Mikhail
  • 4,175
  • 15
  • 31
0

Reflection will allow you to change the contents of any private field. Is it therefore correct to call any object in Java immutable?

Immutability refers to changes that are either initiated by or perceivable by the application.

In the case of string, the fact that a particular implementation chooses to lazily calculate the hashcode is not perceptible to the application. I would go a step further, and say that an internal variable that is incremented by the object -- but never exposed and never used in any other way -- would also be acceptable in an "immutable" object.

parsifal
  • 1
  • 1
  • 1
    Actually I used a public method to change string's state – Evgeniy Dorofeev Mar 07 '13 at 15:47
  • @EvgeniyDorofeev - not in the example you showed. At least, not a public method of the *String* class. If there is a public method of the *String* class that allows you to change its state, then I'll agree: it's not immutable. But I don't know of any such method. – parsifal Mar 07 '13 at 15:49
  • but I called the public method hashCode() in the example and hash field changed. – Evgeniy Dorofeev Mar 07 '13 at 16:00
  • @EvgeniyDorofeev - I seem to have missed the first call of `hashCode()` that returned zero ... let me look ... nope, I don't see it. I see you accessing the internal value of a class, and then calling `hashCode()`. That doesn't contradict my answer. – parsifal Mar 07 '13 at 16:17
0

A class can be immutable while still having mutable fields, as long as it doesn't provide access to its mutable fields.

It's immutable by design. If you use Reflection (getting the declared Field and resetting its accessibility), you are circumventing its design.

Graham Borland
  • 60,055
  • 21
  • 138
  • 179
Atif
  • 942
  • 1
  • 6
  • 19
0

Yes it is correct. When you modified a String like you do in your example, a new String is created but the older one maintain its value.

ftrujillo
  • 1,172
  • 1
  • 16
  • 30