I have class like this:
abstract class Parent {
protected Parent(Raw rawData) {
deserialize(rawData);
}
protected abstract void deserialize(Raw rawData);
}
class Child extends Parent {
final byte firstByte;
public Child(Raw rawdData) { super(rawData); }
protected void deserialize(Raw rawData) {
firstByte = rawData.getFirst();
}
}
So basically any child class that extends Parent will define a deserialize()
to deserialize the rawData to fill in their member variables, and in their constructor they will just do super(rawData)
. The deserialize
function of the child class will automatically execute.
Error message:
Child.java:5: error: cannot assign a value to final variable firstByte
firstByte = rawData.getFirst();
However doing this Java does not allow me to define member variables as final
which is weird because I'm doing initialization in the constructor. What is the best way to do the same functionality but allowing member to be final
?
A final variable can be assigned a value only once. The compiler doesn't check whether a method is called only once; hence, final variables cannot be assigned in methods. (In case of the
deserialize
method the compiler couldn't determine if the method is called only once, even if it would want to. The method is protected and there is nothing which prevents a subclass from calling it twice.) Thus, you can only assign to final member variables in the constructor (or initialize them immediately when you define them).The solution is to make the variable not final. You can still ensure that instances of your class are immutable by restricting access to the variable (make it private) and only provide a getter for it (if you needs its value outside of the class).
Note also that it is better not to call methods from a constructor, especially methods which can be overridden by subclasses. Although it will probably work now if you not depend on the state of the object, you have to realize that when the method is called, the object is not completely constructed yet. If you (or someone else) want to modify that method in the future, you may have forgotten this and introduce hard-to-find bugs. For example, the following little program:
outputs
although the same final string reference is printed two times.
So yes, you should call your
deserialize
method in each of the subclasses' constructor instead of in the superclass constructor, so that each constructor only constructs the part of the object it knows about.