문제
작업중인 코드 기반에서 다음 코드를 발견했습니다.
public final class ConfigurationService {
private static final ConfigurationService INSTANCE = new ConfigurationService();
private List providers;
private ConfigurationService() {
providers = new ArrayList();
}
public static void addProvider(ConfigurationProvider provider) {
INSTANCE.providers.add(provider);
}
...
INSTANCE
로 선언됩니다 final
. 객체를 추가 할 수있는 이유 INSTANCE
? 그것이 최종 사용을 무효화해서는 안됩니다. (그렇지 않음).
나는 대답이 포인터와 기억으로 무언가를해야한다고 가정하지만 확실히 알고 싶습니다.
해결책
final
단순히 객체를 만듭니다 참조 변경할 수 없습니다. 그것이 가리키는 대상은 이것을함으로써 불변이 아닙니다. INSTANCE
다른 객체를 참조 할 수는 없지만, 참조하는 객체는 상태를 변경할 수 있습니다.
다른 팁
결승은 불변이 아닌 것과 같지 않습니다.
final != immutable
그만큼 final
키워드는 참조가 변경되지 않도록하는 데 사용됩니다 (즉, 참조는 새 것으로 대체 할 수 없습니다).
그러나 속성이 자체적이면 수정 가능하면 방금 설명한 것을 수행해도 괜찮습니다.
예를 들어
class SomeHighLevelClass {
public final MutableObject someFinalObject = new MutableObject();
}
이 수업을 인스턴스화하면 속성에 다른 값을 할당 할 수 없습니다. someFinalObject
이 때문에 결정적인.
그래서 이것은 불가능합니다.
....
SomeHighLevelClass someObject = new SomeHighLevelClass();
MutableObject impostor = new MutableObject();
someObject.someFinal = impostor; // not allowed because someFinal is .. well final
그러나 객체가 자체적으로 변한 경우 :
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 ); // prints 3
이것은 귀하의 게시물과 동일한 영향을 미칩니다.
public static void addProvider(ConfigurationProvider provider) {
INSTANCE.providers.add(provider);
}
여기에서 인스턴스의 값을 변경하지 않으면 내부 상태를 수정하고 있습니다 (via, providers.add method).
클래스 정의를 다음과 같이 변경 해야하는 경우 :
public final class ConfigurationService {
private static final ConfigurationService INSTANCE = new ConfigurationService();
private List providers;
private ConfigurationService() {
providers = new ArrayList();
}
// Avoid modifications
//public static void addProvider(ConfigurationProvider provider) {
// INSTANCE.providers.add(provider);
//}
// No mutators allowed anymore :)
....
그러나, 그것은 의미가 없을 수도 있습니다 :)
그건 그렇고, 당신도해야합니다 액세스를 동기화합니다 기본적으로 같은 이유로.
오해의 열쇠는 질문의 제목에 있습니다. 그것은 아닙니다 물체 최종입니다 변하기 쉬운. 변수의 값은 변경 될 수 없지만 그 내 데이터는 할 수 있습니다.
참조 유형 변수를 선언 할 때 해당 변수의 값은 객체가 아니라 참조입니다.
결정적인 단지 참조를 변경할 수 없다는 것을 의미합니다. 인스턴스를 다른 참조가 최종적으로 선언 된 경우 인스턴스를 다른 참조로 재 할당 할 수 없습니다. 물체의 내부 상태는 여전히 변이합니다.
final ConfigurationService INSTANCE = new ConfigurationService();
ConfigurationService anotherInstance = new ConfigurationService();
INSTANCE = anotherInstance;
컴파일 오류를 던질 것입니다
한 번 a
final
변수가 할당되었으며 항상 동일한 값을 포함합니다. 만약final
변수는 객체에 대한 참조를 보유한 다음 객체의 상태가 객체의 작업에 의해 변경 될 수 있지만 변수는 항상 동일한 객체를 참조합니다. 배열은 물체이기 때문에 배열에도 적용됩니다. 만약final
변수는 배열에 대한 참조를 보유하고 배열의 구성 요소는 배열에서 작업에 의해 변경 될 수 있지만 변수는 항상 동일한 배열을 참조합니다.
다음은 안내서입니다 불변의 물체를 만듭니다.
최종적이고 불변은 같은 것이 아닙니다. 최종은 참조를 재 할 수 없으므로 말할 수 없다는 것을 의미합니다.
INSTANCE = ...
불변은 물체 자체를 수정할 수 없음을 의미합니다. 이것의 예는 java.lang.String
수업. 문자열 값을 수정할 수 없습니다.
Java는 언어에 내장 된 불변성의 개념이 없습니다. 방법을 돌연변이터로 표시하는 방법은 없습니다. 따라서 언어는 물체의 불변성을 시행 할 방법이 없습니다.