I was told that, I misunderstand effects of final
. What are the effects of final
keyword?
Here is short overview of what I think, I know:
Java final modifier (aka aggregation relation)
primitive variables: can be set only once. (memory and performance gain)
objects variables: may be modified, final applies to object reference.
fields: can be set only once.
methods: can't be overridden, hidden.
classes: can't be extended.
garbage collection: will force Java generational garbage collection mark-sweep to double sweep.
Can's and Cant's
- Can make clone fail (this is both good and bad)
- Can make immutable primitives aka const
- Can make blank immutable - initialized at creation aka readonly
- Can make objects shallowly immutable
- Can make scope / visibility immutable
- Can make method invocation overhead smaller (because it does not need virtual table)
- Can make method arguments used as final (even if thy are not)
- Can make objects threadsafe (if object is defined as final, it wont make method arguments final)
- Can make mock tests (not that you could do anything about it - you can say bugs are intended)
- Can't make friends (mutable with other friends and immutable for rest)
- Can't make mutable that is changed to be immutable later (but can with factory pattern like fix)
- Can't make array elements immutable aka deeply immutable
- Can't make new instances of object (this is both good and bad)
- Can't make serialization work
There are no alternatives to final
, but there is wrapper + private and enums.
Final keyword is usually used to preserve immutability. To use final for classes or methods is to prevent linkages between methods from being broken. For example, suppose the implementation of some method of class X assumes that method M will behave in a certain way. Declaring X or M as final will prevent derived classes from redefining M in such a way as to cause X to behave incorrectly.
Answering each of your points in turn:
Yes, but no memory gain, and no performance gain. (Your supposed performance gain comes from setting only once ... not from
final
.)Yes. (However, this description miss the point that this is entirely consistent with the way that the rest of the Java language deals with the object / reference duality. For instance, when objects are passed as parameters and returned as results.)
The real answer is: same as for variables.
Yes. But also note that what is going on here is that the
final
keyword is being used in a different syntactic context to mean something different tofinal
for an field / variable.Yes. But also see note above.
This is nonsense. The
final
keyword has no relevance whatsoever to garbage collection. You might be confusingfinal
with finalization ... they are unrelated.But even finalizers don't force an extra sweep. What happens is that an object that needs finalization is set on one side until the main GC finishes. The GC then runs the finalize method on the object and sets its flag ... and continues. The next time the GC runs, the object is treated as a normal object:
(Your characterization - "Java generational garbage collection mark-sweep" is garbled. A garbage collector can be either "mark-sweep" OR "generational" (a subclass of "copying"). It can't be both. Java normally uses generational collection, and only falls back to mark-sweep in emergencies; i.e. when running out of space or when a low pause collector cannot keep up.)
I don't think so.
Yes.
Yes ... though I've never heard the term "blank immutable" used before.
Object mutability is about whether observable state may change. As such, declaring attributes
final
may or may not make the object behave as immutable. Besides the notion of "shallowly immutable" is not well defined, not least because the notion of what "shallow" is cannot be mapped without deep knowledge of the class semantics.(To be clear, the mutability of variables / fields is a well defined concept in the context of the JLS. It is just the concept of mutability of objects that is undefined from the perspective of the JLS.)
Terminology error. Mutability is about object state. Visibility and scope are not.
In practice, this is irrelevant. A modern JIT compiler does this optimization for non-final methods too, if they are not overridden by any class that the application actually uses. (Clever stuff happens ...)
Huh? I cannot parse this sentence.
In certain situations yes.
Yes, if you mean if class is final. Objects are not final.
Doesn't parse.
Java doesn't have "friends".
Yes to the first, a
final
field can't be switched from mutable to immutable.It is unclear what you mean by the second part. It is true that you can use a factory (or builder) pattern to construct immutable objects. However, if you use
final
for the object fields at no point will the object be mutable.Alternatively, you can implement immutable objects that use non-final fields to represent immutable state, and you can design the API so that you can "flip a switch" to make a previously mutable object immutable from now onwards. But if you take this approach, you need to be a lot more careful with synchronization ... if your objects need to be thread-safe.
Yes, but your terminology is broken; see comment above about "shallow mutability".
No. There's nothing stopping you making a new instance of an object with final fields or a final class or final methods.
No. Serialization works. (Granted, deserialization of
final
fields using a customreadObject
method presents problems ... though you can work around them using reflection hacks.)Correct.
Yes, modulo that (strictly speaking) an unsynchronized getter for a non-final field may be non-thread-safe ... even if it is initialized during object construction and then never changed!
Solves a different problem. And
enums
can be mutable.