문제

작업중인 코드 기반에서 다음 코드를 발견했습니다.

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는 언어에 내장 된 불변성의 개념이 없습니다. 방법을 돌연변이터로 표시하는 방법은 없습니다. 따라서 언어는 물체의 불변성을 시행 할 방법이 없습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top