I know this is fairly simple topic, but I really want to wrap my head around it.
This is what I\'m trying to do, but it doesn\'t like the final modifier. Is there an
private final long mId;
final
reference cann't be modified at runtime as per java spec. So, once you declared it as final, mId can't point to something else throughout its lifetime (Unless you use reflection (or) wrap the value in object and modify it through other reference).
You can't. But you can guarantee no external object changes it if it's private and you don't have a setter for it.
Alternatively, you can wrap the long value in another class - LazyImmutableLong
. But this is a more verbose approach, and you probably don't need it (note: the class below is not thread-safe)
class LazyImmutableLong {
private Long value;
public void setValue(long value) {
if (this.value != null) {
return; // the value has already been set
}
this.value = value;
}
public long getValue() {return value;}
}
And in your activity
private LazyImmutableLong id = new LazyImmutableLong();
public void onCreate(..) {
id.setValue(..);
}
The following Worm
(Write-Once-Read-Many) class could help in this kind of scenario.
We could create a nested Wrapper
class, that stores the final variable you need. To initialize this variable, you just should call a constructor of the wrapper
object. When you call the method getData()
, you will get a reference of the final variable in case it is initialized, otherwise, you will get null
.
The methods getData()
and setData(T data)
are required to be thread-safe. To provide it, we use a volatile
modifier for the wrapper
object. Reading a volatile variable is synchronized and writing to a volatile variable is synchronized, too. Even though some efforts were made to make this code thread-safe I didn't test it in this respect. Depending on the level of thread safety you may consider to make setter and getter synchronized.
public class Worm<T> {
private volatile Wrapper<T> wrapper;
public Worm() {}
public Worm(T data) throws IllegalAccessError
{
setData(data);
}
public T getData()
{
if (wrapper == null)
return null;
return wrapper.data;
}
public void setData(T data) throws IllegalAccessError
{
if (wrapper != null)
throw new IllegalAccessError();
else
wrapper = this.new Wrapper<>(data);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Worm<T> other = (Worm<T>) obj;
return Objects.equals(this.getData(), other.getData());
}
@Override
public int hashCode() {
return Objects.hashCode(this.getData());
}
final private class Wrapper<T> {
final private T data;
Wrapper(T data) {
this.data = data;
}
}
}
You can set a final
variable only in a constructor or in an initializer. Regular methods cannot change the value of variables declared final
.
You can set later a global final Variable only in your constructor. Example:
public class ClassA {
private final long mID;
public ClassA(final long mID) {
this.mID = mID;
}
}
In this case in each constructor you have to initialize the final variable.
you have to initialize the constructor as soon as you create it, or you could initialize it at the max, in the constructor. Not later than that..