Ser definitivo no es lo mismo que ser inmutable.
final != immutable
La final
palabra clave se usa para asegurarse de que la referencia no se cambie (es decir, la referencia que tiene no se puede sustituir por una nueva)
Pero, si el atributo es self es modificable, está bien hacer lo que acaba de describir.
Por ejemplo
class SomeHighLevelClass {
public final MutableObject someFinalObject = new MutableObject();
}
Si instanciamos esta clase, no podremos asignar otro valor al atributo someFinalObject
porque es final .
Entonces esto no es posible:
....
SomeHighLevelClass someObject = new SomeHighLevelClass();
MutableObject impostor = new MutableObject();
someObject.someFinal = impostor;
Pero si el objeto en sí mismo es mutable así:
class MutableObject {
private int n = 0;
public void incrementNumber() {
n++;
}
public String toString(){
return ""+n;
}
}
Entonces, el valor contenido por ese objeto mutable puede cambiarse.
SomeHighLevelClass someObject = new SomeHighLevelClass();
someObject.someFinal.incrementNumber();
someObject.someFinal.incrementNumber();
someObject.someFinal.incrementNumber();
System.out.println( someObject.someFinal );
Esto tiene el mismo efecto que tu publicación:
public static void addProvider(ConfigurationProvider provider) {
INSTANCE.providers.add(provider);
}
Aquí no está cambiando el valor de INSTANCE, está modificando su estado interno (a través del método Suppliers.add)
si desea evitar que la definición de la clase deba cambiarse así:
public final class ConfigurationService {
private static final ConfigurationService INSTANCE = new ConfigurationService();
private List providers;
private ConfigurationService() {
providers = new ArrayList();
}
....
Pero, puede que no tenga mucho sentido :)
Por cierto, también tienes que sincronizar el acceso básicamente por la misma razón.