การเป็นขั้นสุดท้ายไม่เหมือนกับการไม่เปลี่ยนรูป
final != immutable
final
คำหลักที่ถูกนำมาใช้เพื่อให้แน่ใจว่าการอ้างอิงจะไม่เปลี่ยนแปลง (นั่นคือการอ้างอิงที่ยังไม่สามารถทดแทนด้วยใหม่)
แต่ถ้าแอตทริบิวต์นั้นเป็นของตัวเองสามารถแก้ไขได้ก็สามารถทำตามที่คุณได้อธิบายไว้ได้
ตัวอย่างเช่น
class SomeHighLevelClass {
public final MutableObject someFinalObject = new MutableObject();
}
ถ้าเรายกตัวอย่างชั้นนี้เราจะไม่สามารถที่จะกำหนดค่าอื่น ๆ ที่จะแอตทริบิวต์someFinalObject
เพราะมันเป็นครั้งสุดท้าย
ดังนั้นจึงเป็นไปไม่ได้:
....
SomeHighLevelClass someObject = new SomeHighLevelClass();
MutableObject impostor = new MutableObject();
someObject.someFinal = impostor;
แต่ถ้าวัตถุที่เป็นตัวมันเองเปลี่ยนแปลงได้เช่นนี้:
class MutableObject {
private int n = 0;
public void incrementNumber() {
n++;
}
public String toString(){
return ""+n;
}
}
จากนั้นค่าที่อยู่ในวัตถุที่เปลี่ยนแปลงได้นั้นอาจเปลี่ยนแปลงได้
SomeHighLevelClass someObject = new SomeHighLevelClass();
someObject.someFinal.incrementNumber();
someObject.someFinal.incrementNumber();
someObject.someFinal.incrementNumber();
System.out.println( someObject.someFinal );
สิ่งนี้มีผลเช่นเดียวกับโพสต์ของคุณ:
public static void addProvider(ConfigurationProvider provider) {
INSTANCE.providers.add(provider);
}
ที่นี่คุณไม่ได้เปลี่ยนค่าของ INSTANCE คุณกำลังแก้ไขสถานะภายใน (ผ่านวิธีการให้บริการเพิ่ม)
หากคุณต้องการป้องกันไม่ให้เปลี่ยนนิยามคลาสเช่นนี้:
public final class ConfigurationService {
private static final ConfigurationService INSTANCE = new ConfigurationService();
private List providers;
private ConfigurationService() {
providers = new ArrayList();
}
....
แต่มันอาจไม่สมเหตุสมผลเท่าไหร่ :)
อย่างไรก็ตามคุณต้องซิงโครไนซ์การเข้าถึงโดยทั่วไปด้วยเหตุผลเดียวกัน