Subclases inmutables

I'm currently developping a multithreaded framework. To avoid side effects, I would like to require that all data manipulated by the framewok has to be immutable.

So does a way exist in Java to specify I want all subclasses of a given class or all classes implementing a given interface to be immutable?

preguntado el 04 de julio de 12 a las 01:07

@Traroth: That would potentially allow you to detect it via reflection, but not enforce it to begin with (compile time). Some of the discussion in this thread es relevante. -

@Traroth: "and check if the type is final and also if all fields of the type are final" y que estos campos are immutable. You could have a private final Foo foo in your subclass - the foo reference can't change, but if Foo is mutable, so is your subclass. -

@Traroth the @Immutable from JSR-305 already fills this need. However, the problem is not in the creating of an annotation, it's in being able to enforce/check that it's actually upheld. Depending on how strict you want to be, you might have to go down routes such as installing your own Security Manager, to check that reflection isn't being used to mutate private final fields. If you're not in a situation to control that, there's always going to be ways for clients to get around your requirement. -

@Traroth The @Immutable annotation did not get into Java 7, and (AFAIK) is unlikely to be added to Java 8. The annotation is available in the jar I linked to in previous comment, under the package javax.annotation.concurrent. However, it doesn't trigger any behaviour and there are very few automated tools that take advantage of it, so the annotation is mostly for documentation purposes. -

@Voo most if not all functional programming languages even do immutability by default. (Examples: Haskell, OCaml.) Among imperative languages, immutability has started to gain attention, but most languages do it in an half-assed way (const in C++); I'd look in modern imperative languages to find one that has it (Kotlin, maybe). -

3 Respuestas

Recomiendo mirar en Detector de mutabilidad. It performs static analysis to determine if a given class is immutable. It could be used to add something akin to a runtime assertion, i.e. you could choose to throw an exception if you are passed an instance of a mutable class. Note that it could analyse the actual, concrete class at runtime, including subclasses or implementations of an interface that you have defined.

It is still a pre-1.0 release, and has issues with java.lang.String, but it could be usable. If it's close to what you're looking for, but doesn't quite do what you want, I recommend contacting the mailing list or filing a bug report, as I believe the project maintainer is quite a reasonable guy. Disclaimer: that maintainer is me ;-)

Respondido 04 Jul 12, 22:07

I can see some uses to your tool... :-) - Alexis Dufrenoy

Thanks. I'm not going to say it's perfect, but I think it's as close as you're going to get with any open source tool. The question then becomes "is it close enough?" :) - Grundlefleck

Actually, I think I will try to use your code to write the annotation mentionned above. I write an annotation but the immutability detection is highly imperfect.... - Alexis Dufrenoy

There is no way to require immutability of subclasses. You can make sure that subclasses of your classes do not mutate your state by not providing setters and keeping your instance variables private, but if subclasses declare their own instance variables, they have full control over them.

As far as interfaces go, the only thing you can do is to not provide setters. However, implementations can provide setters of their own.

Respondido 04 Jul 12, 01:07

To make a class truly immmutable, all members of the class must be immutable and the class itself must be final. This ensures the object cannot be changed from within the class or outside of the class.

To make members inside the class immutable, this means more than just making them final. Por ejemplo

private final List<String> strings = new LinkedList<String>();

strings is final but can still be changed because items can be added and removed from the list. In this case, you could wrap it in an unmodifiable collection. Even this is not perfect though because the objects in your list could be mutable (Strings are not obviously, but your list might have mutable objects in them where you could do list.get(index).mutator(...))

There is no silver bullet as to how to make an object immutable. If it provides any methods that mutate the object, then it cannot be immutable.

As for making a class final, to achieve guaranteed immutability this necessary. Imagine the case,

class MyImmutableClass {
    private final String name

class MutableClass extends MyImmutableClass {
    private String mutableValue;

    public void setMutableValue(String mutableValue...)

void doSomething(MyImmutableClass c) {...}

No hay garantía de que doSomething is actually dealing with an immutable instance but rather it could be dealing with a mutable subclass. As you can see, this would pose a problem for working with interfaces. There is no way to guarantee that an implementor of an interface is immutable.

El @Immutable annotation does not guarantee immutability, but rather just states that the class is telling you it is immutable, but there is no good way to enforce that.

If you are able to work in groovy the @Immutable annotation has some effect as it does a lot of these techniques above that I mentioned.

Respondido 04 Jul 12, 23:07

Note, you can also achieve the same effect as declaring your class final by having only private scope constructors. (Probably not worth complicating the answer to explain this, but is worth noting imo). - Grundlefleck

Sure, you could do that. I think final more clearly expresses your intent though. - Jeff Storey

An object which holds a references to mutable objects can be immutable, if (1) within its constructor, it creates the mutable objects and mutates them as desired; (2) it does not allow a reference to any of the encapsulated objects to be leaked, directly or indirectly, to any code which might try to mutate them; (3) the immutable object will never mutate itself or any encapsulated objects after any reference to it has been exposed to the outside world. - Super gato

If I have a final class C with final attribute members, if those attributes contain non-final members, is the C class really immutable? And don't even talk about reflection. When I asked this question, I didn't get immutability was such a complicated matter in Java... - Alexis Dufrenoy

No it's not truly immutable. You could do getSomeList().setSomeAttribute(x). - Jeff Storey

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.