4

Possible Duplicate:
Implement a final class without the “final” keyword

I want to create an immutable class in Java without using the final keyword.

Community
  • 1
  • 1
developer
  • 9,116
  • 29
  • 91
  • 150

6 Answers6

13

I think smt like should work fine

class Immutable {
    private int i;
    public static Immutable create(int i){
        return new Immutable(i);
    }
    private Immutable(int i){this.i = i;}
    public int getI(){return i;}
}

But final is preferable.

Stan Kurilin
  • 15,614
  • 21
  • 81
  • 132
  • +1: this is the right answer. – Tomas Narros Mar 23 '11 at 10:07
  • @Tomas: it's not the *only* right answer. You could also have `if (getClass()!=ThisClass.class) throw new IllegalStateException();` in your code to "simulate" `final`. – Joachim Sauer Mar 23 '11 at 10:25
  • 2
    @Joachim: This wouldn't prevent extending the class and overriding the methods with this validation (without using `final`, again). Getting the class don't compile would be preferable IMO. – Tomas Narros Mar 23 '11 at 10:27
  • 1
    @Tomas: of course it would be preferable, but we're working within artificial constraints already. – Joachim Sauer Mar 23 '11 at 10:42
  • is really this is the right answer. AFAIK here there are no guarantees of safe publication. due to effect of reordering you can see non null reference of Immutable before this.i = i actually happens. so therefore you can see value of i as 0. and hence it is mutable. You need to have a memory barrier to guarantee safe publication of Immutable instances. Am talking here for Immutable Objects not about whether we can extend capabilities of a class with or without final keyword. – veritas Aug 21 '13 at 05:52
  • @veritas There is simple rule, Do not pass `this` anywhere from your constructor. It seems for me, that if you don't violate this rule this "code patter" should work well. – Stan Kurilin Aug 22 '13 at 14:54
  • @StasKurilin yes right. escaping this reference even violates final semantics. But i am not talking about escaping this reference. I am talking about reordering. There is nothing in the above code which guarantees that this.i = i happens before the assignment of reference when more than one thread is involve. Please see http://cs.oswego.edu/pipermail/concurrency-interest/2013-February/010689.html and http://stackoverflow.com/questions/14624365/immutability-and-reordering . These links do not answer the above question but they establish effect of reordering without proper barrier. – veritas Aug 22 '13 at 15:09
  • @veritas I get you. Seems interesting. I'm not so sure about this stuff. You could be right. – Stan Kurilin Aug 22 '13 at 18:06
4

The final keyword won't make your class inmutable. It will avoid your class to be extended from another class.

public final class Foo {
   //....
}

public class Bar extends Foo {
   //COMPILATION ERROR!
}

An adecuated class design is what will make you class inmutable, as you can see at duffymo answer.

Note that you can declare as final the fields that you will initialize at the constructor:

class Foo {
    private final int state

   public Foo(int v) {
      this.state=v;
   }

   //....
}

The difference is that, while at duffymo example, the value ccould be changed from inner routines (i.e, a method adds one to the value, kind of a counter), at my example you wouldn't be able to do so.

Let's try to avoid absolutely the use of the final keyword:

public class Foo {

   private int state;


   private Foo(int v) {
       this.state=v;
   }

   public static Foo getInstance(int value) {
      return new Foo(value);
   }

}

You only can get an instance of Foo accesing the Foo.getInstance method.

But anyway, you can extend the Foo class and make it mutable I was wrong here. I won't compile, as you can acceess the Foo constructor.

public class Bar extends Foo {
    private int ohNopes;

    //COMPILATION ERROR!
    public Bar(int v) {
        this.ohNopes=v; 
    }
}

So, it seems it can be done, after all.

Tomas Narros
  • 13,390
  • 2
  • 40
  • 56
  • the OP doesn't want to use the `final` keyword and you have. – dogbane Mar 23 '11 at 09:40
  • @dogbane: Read my whole answer, not just the code snippets. I recommend the duffymo answer, and offer some additional comments on the `final` keyword. (I don't understand why can't be used, anyway) – Tomas Narros Mar 23 '11 at 09:45
3

The problem with an immutable class not being final is that, subclasses may not be immutable.

Here is an example from the Java API, java.lang.String is immutable and final, if a string is passed to one of your methods you can be sure that it will remain in a consistent state.

the following will not compile because String is final:

public class MyString extends java.Lang.String {
    public MyString(String original) {
        Super(original);
    }

    @Override
    public String toString() {
        return String.valueOf(System.currentTimeMillis());
}

On the other hand, java.ma.BigDecimal itself is immutable, but it is not final and allowed to be subclassed. This opens up a range of issues. If a BigDecimal is passes to one of your methods you can't rely on the fact that no one has overridden BigDecimal like you can with String. subclasses of BigDecimal could potentially replace its methods with others which give unpredictable results.

The following will compile because BigDecimal is not immutable:

public class MyBigDecimal extends java.math.BigDecimal {
    public MyBigDecimal(double val) {
        super(val);
    }

    private int count = 0;
    // override intValue which changes the state of this instance
    @Override
    public int intValue() {
        return count++; 
    }

    // rinse and repeat for the rest of the BigDecimal methods... 
}

You cannot rely on he state of BigDecimal instances passed into your code, you should make Defensive copies of non final classes if you need to rely on their immutability.

krock
  • 28,904
  • 13
  • 79
  • 85
1

I can't imagine why you object to using final, but here's a class that will get the job done. I know there are subtleties regarding serialization and reflection, but this can't be changed without special shenanigans:

public class Immutable
{
    private int value;

    public Immutable(int v)
    { 
        this.value = v;
    }

    public int getValue() { return this.value; }
}
duffymo
  • 305,152
  • 44
  • 369
  • 561
  • 6
    I could still create a subclass that is mutable (by overwriting `getValue()` or introducing additional, mutable properties). – Joachim Sauer Mar 23 '11 at 09:35
  • You mean that I can't inherit form this class and override the method getValue() ? – Damian Leszczyński - Vash Mar 23 '11 at 09:37
  • @duffymo.The reason final is required is this: Suppose someone overrides a mutable class UM and makes the subclass M as mutable, then how do you handle a scenario liek UM var= new M; Now apis may expect the object referred in var to be immutable – Suraj Chandran Mar 23 '11 at 09:39
  • 1
    Like I said, "special shenanigans". The requirement was "no final", so that's what I posted. I'm not arguing that it's necessary to prevent overriding; I'm meeing the stated requirement. You're doing a fine job of pointing out how the requirements are inconsistent. – duffymo Mar 23 '11 at 11:25
0

The class should set all its values in the constructor, and provide no setters (methods that modify class members).

Quick Joe Smith
  • 8,074
  • 3
  • 29
  • 33
-1

You can create a class then create a .jar and use the jar as resource.

  • What do you mean? I think this has nothing to do with inmutable classes – Tomas Narros Mar 23 '11 at 09:51
  • 3
    To be honest i totally mis understand the OP question. I was thinking that while we work in a developement team sometime we want to have some class with implementation that none of our coworker can change. This is how i understood immutable at the beginning. But You have right, that this does not have nothing to do with immutable classes. – Damian Leszczyński - Vash Mar 23 '11 at 09:57
  • Vash you are right this is a practical requirement that none of our coworker should not be able to change. Although I don't endorse your suggestion, Some practices look weird from out side the project. – kiran.kumar M Mar 23 '11 at 10:15