4

This post talks about immutable objects being transitively reachable from a final field:

Immutability doesn't mean "does not change" in Java. It means "is transitively reachable from a final field, has not changed since the final field was set, and a reference to the object containing the final field did not escape the constructor".

For the the following code,

public class A() {
    private String myString;
    public A(String myString){
        this.myString = myString;
    }
    public String getMyStringAndYours(){
        return myString.concat("yours");
    }
}

are A instances transitively reachable from a final field? I think so because:
1. myString.value is final
2. myString is reachable from myString.value
3. An instance of A, a, is reachable from a.myString

Side question: Is a immutable?

damat-perdigannat
  • 5,780
  • 1
  • 17
  • 33

3 Answers3

5

I would set aside transitively reachable for a moment and concentrate on the difference between final and immutability.

class MyObject {
int a;
void setA(int val){
a=val;
}
}

final MyObject obj = new MyObject(); 

now,since obj reference is final you will get a compilation error if you try to do

obj = new MyObject(); // you can't re-initialize a final reference.

But what you can do :

obj.setA(5); // perfectly valid.

you can change the state of object referenced by obj but cannot re-initialize obj to some other object

Now, if all fields inside MyObject were final and all setters were private (or absent), then there will be no way of doing

obj.setA(5); 

An immutable object is one whose internal state cannot change.

Now, coming back to transitively reachable. If Object A s composed of Object B and in-turn Object B has Object C (composition). Your Object A isn't truly immutable unless all transitively reachable objects are both immutable and final i.e, a.b.c here a ,b and ,c should be final to prevent re-assigning of reference to another object. Also, you should ensure that c is not shared (escapes the scope of A) whenever a is created. If it is shared, then any other object can change it.

Edit :

Strings are immutable so, you just need to make them final so that their enclosing class is immutable .

TheLostMind
  • 35,966
  • 12
  • 68
  • 104
  • It's a little confusing because from what I understand in the blogger (in the question)'s definition, immutable objects also have to be reachable from final fields. Based on @JBNizet's definition, myString is not reachable from a final field, so I'm guessing myString is not immutable. – damat-perdigannat Aug 20 '14 at 07:17
  • 1
    @b16db0 - You need to *recursively* make sure that all fields are final and references don't escape the scope. This will ensure immutability. For Strings, only *final* is enough as they are implicitly *immutable*. – TheLostMind Aug 20 '14 at 08:52
1

A would be "immutable enough". Because after construction, the field myString cannot be changed (at least in the context provided by the code), the state of A does not change, making it immutable.

Also, String#concat(String) doesn't change the state of String, as specified in the documentation, it creates a new String, making sure that String is immutable, and keeping A immutable as well.

  • It's a little confusing because I'm guessing that there could be an instance here (causing a NullPointerException) when thread 1 calls the constructor and thread 2 calls getMyStringAndYours? Here's a link: http://stackoverflow.com/questions/1621435/not-thread-safe-object-publishing – damat-perdigannat Aug 20 '14 at 07:29
1

You have the reachability in the reverse order. Consider these classes:

public class SomeBean {
    private String a;
}

public class SomeOtherBean {
    private SomeBean someBean;
    ...
}

public class Foo {
    private final SomeOtherBean someOtherBean;
    private /* non-final */ SomeOtherBean someOtherBean2;
}

Then Foo.someOtherBean.someBean and Foo.someOtherBean.someBean.a are transitively reacheable from a final field, since Foo.someOtherBean is final, and from Foo.someOtherBean, you can reach Foo.someOtherBean.someBean and Foo.someOtherBean.someBean.a by following the references.

On the other hand, Foo.someOtherBean2.someBean and Foo.someOtherBean2.someBean.a are not transitively reacheable from a final field, since Foo.someOtherBean is not final.

JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
  • It's a little confusing. That means myString is not immutable, right? myString is not accessible from a final field. – damat-perdigannat Aug 20 '14 at 07:37
  • 2
    What is confusing is the wording of the quote in your question. myString is a reference. We're discussing about immutability of classes. String is immutable. The question is: "is the class A immutable". And the answer is: to be truly immutable, myString should be final, because for a class to be immutable, its fields must be final. What the post author says basically is that an immutable class Foo may contain instances of mutable classes, as long as these instances are reachable from a final field of Foo. – JB Nizet Aug 20 '14 at 07:53
  • 1
    For a good explanation of immutability, I suggest you read "Concurrency in practice" from Brian Goetz. – JB Nizet Aug 20 '14 at 07:55
  • I think get it now. Just to confirm, calling `new A("someString")` will always be thread safe even though A is not immutable? That is because String ("someString") is immutable. – damat-perdigannat Aug 20 '14 at 08:03
  • 2
    No, it won't always be thread-safe. It will only be thread-safe if the instance of A is properly published to other threads. To be absolutely thread-safe, myString should be final. This is discussed in JCIP. – JB Nizet Aug 20 '14 at 08:11
  • Can you explain why? There's a new instance of A for every thread. – damat-perdigannat Aug 20 '14 at 08:15
  • Actually, I have a question for that here in StackOverflow. Here's the link in case you want to see it: http://stackoverflow.com/questions/25359084/have-these-two-java-io-file-thread-safety-issues-been-evaded – damat-perdigannat Aug 20 '14 at 08:17
  • 1
    @b16db0 - If two or more threads don't work ont same object at the same time (i.e, each thread has its own instance of A) then you don't need to worry about thread safety or immutability(usually). As JBNizet says, if myString is not final, any other (or the same) thread can **reassign** myString reference to some other String Object. – TheLostMind Aug 20 '14 at 08:20
  • 1
    See chapter 3.4 of http://books.google.fr/books?id=EK43StEVfJIC&printsec=frontcover&hl=fr#v=onepage&q&f=false, which discusses it in details. Without safe publication of your "effectively (but not absolutely) immutable" object, another thread might not see the actual value of the myString field. Making it final removes this problem. – JB Nizet Aug 20 '14 at 08:21
  • 1
    @JBNizet - In the OPs link,Instead of using *is transitively reachable from a final field*, wouldn't it have been better to use - "all fields must be recursively final and no reference should escape the scope*? – TheLostMind Aug 20 '14 at 08:54
  • 1
    @TheLostMind: All fields must not be *recursively* final. You can use a mutable class to implement an immutable class.Of course, you must not mutate the mutable object after the immutable object has been constructed, and you must not share it (using a getter, for example). – JB Nizet Aug 20 '14 at 10:00
  • 1
    @JBNizet - if the inner object is immutable (but is not declared as final), but the outer object isn't, then I can easily replace outer.inner = new inner(). Making inner reference as *final* prevents this right? – TheLostMind Aug 20 '14 at 10:28
  • 1
    Yes. You can't assign a new value to a final variable. – JB Nizet Aug 20 '14 at 10:38