2013-09-27 4 views
14

Если переменная экземпляра устанавливается окончательное его значение не может быть изменено, какПочему переменная класса конечного экземпляра в Java?

public class Final { 

    private final int b; 

    Final(int b) { 
     this.b = b; 
    } 

    int getFinal() { 
     return b = 8; // COMPILE TIME ERROR 
    } 
} 


Где-то в коде я видел экземпляр класса переменной HashMap объявлен как окончательное

private final Map<String, Object> cacheMap = new HashMap<String, Object>(); 

Я не мог понять, почему это объявлено так? Обычно в этом случае он объявляется. Означает ли это, что если я помещу карту хэша, то я не смог бы изменить ее значение?

Edit:
Если cacheMap, который объявлен как окончательный передается в качестве параметра к другому классу, то ошибка не показан для окончательной, если я изменю свою ссылку. Почему это так?

class CacheDTO { 

    private Map conditionMap; 

    public Map getConditionMap() { 
     return conditionMap; 
    } 

    public void setConditionMap(Map conditionMap) { 
     this.conditionMap = conditionMap; 
    } 
} 

Тогда

private final Map<String, Object> cacheMap = new HashMap<String, Object>(); 
CacheDTO cc = new CacheDTO(); 
cc.setConditionMap(cacheMap); 
Map<String, Object> cacheMapDeclaredAsFinal = cc.getConditionMap(); 
Map<String, Object> newMap = new HashMap<String, Object>(); 
cacheMapDeclaredAsFinal = newMap; // In this case no error is shown. Though cacheMapDeclaredAsFinal reference is obtained by calling cc.getConditionMap() and cacheMapDeclaredAsFinal refers to final. 

ответ

16

final не имеет ничего общего с содержанием объекта переменная имеет в виду. Вы не сможете изменять значение переменной и ссылаться на другой объект.

33

Вы не можете изменить корзину. Тем не менее вы можете изменить фрукты внутри.

От Language specification # chapter 14.12.4

После окончательного переменная была назначена, она всегда содержит то же значение. Если конечная переменная содержит ссылку на объект, то состояние объекта может быть изменено операциями над объектом, но переменная всегда будет ссылаться на один и тот же объект.

При объявлении field или reference финал, вы должны установить значение один раз к тому времени, выходы конструктора.

Вы можете присвоить значение этой переменной только в конструкторе.

private final Map<String,Object> CacheMap = new HashMap<String,Object>(); 

здесь вы можете сделать

CacheMap.put(..... 

с в классе.

, но вы не можете сделать

CacheMap = something. //compile error. 

Вы должны знать разницу между value и reference.

Редактировать

Здесь

Map<String, Object> cachemapdeclaredasfinal = cc.geConditionMap(); 

Map<String, Object> newMap = new HashMap<String, Object>(); 

cachemapdeclaredasfinal = newMap; // In this case no error is shown 

Причина,

С cachemapdeclaredasfinal не новая карта, это еще одна ссылка conditionMap

при создании нового экземпляра, как это

Map<String, Object> cachemapdeclaredasfinal = 
           new HashMap<String, Object>(cc.geConditionMap()); 

Эта ошибка исчезает. так как вы использовали новый.

Edit 2:

private Map conditionMap; 

public void setConditionMap(Map ConditionMap) { 
     this.conditionMap = conditionMap; 
    } 
    private final Map<String, Object> CacheMap = new HashMap<String, Object>(); 
    CacheDto cc = new CacheDto(); 
    cc.setConditionMap(CacheMap); 
    Map<String, Object> cachemapdeclaredasfinal = cc.geConditionMap(); 
    Map<String, Object> newMap = new HashMap<String, Object>(); 
cachemapdeclaredasfinal = newMap; 

Вот вам, что вы смущены это.

Вы назначаете один final объявлен map некоторому нормальному (не final) map. Когда вы восстановили этот нормальный только вы получаете, а это не final, так что вы можете использовать его/assign.

В Short

normalMap= finalMap; //no error since normalMap is not final 
finalMap =normalMap;// compiler error since normalMap is final 
+0

Я отредактировал некоторый пункт на вопросе. –

+0

@abishkarbhattarai Я обновил. Надеюсь, это поможет. –

+0

@ sᴜʀᴇsʜᴀᴛᴛᴀ Хорошо Объяснение.Но я могу пояснить одно, почему finalMap.put (....) не имеет никакой ошибки, bcz изменяет конечную переменную, поскольку состояния Java Rules Конечная переменная константа не может быть изменена. Итак, почему ошибка компиляции в finalMap.put (...) ??? – artapart

0

Это означает, что hasmap не может быть изменен. Элементы внутри хэш-карты не привязаны к окончательному разделителю.

private static final HashMap<K, V> map = new HashMap<K, V>(); 

public void foo(K k, V v) { 
    map.push(k, v); //This is allowed 
    map = new HashMap<K, V> //This is not allowed 
} 
0

Этот вопрос может помочь вам: http://www.stackoverflow.com/questions/40480/is-java-pass-by-reference

Из того, что я понимаю, это то, что на самом деле происходит: Когда вы передаете объект в метод с Java, вы в основном передается указатель объект. Таким образом, когда вы вызываете cc.geConditionMap(), вы в основном возвращаете указатель. Когда вы меняете его, вы фактически не меняете объект. Вы делаете свою копию указателя на другую карту.

Ваша копия указателя не защищена окончательным, так как вы сохранили копию в переменной, отличной от конечной.

-1

Предположим, что final Map map = new HashMap(); новое: отвечает за создание объекта в куче, который имеет значение

Ссылка на «карту» будет создана в стеке, которое является окончательным.

The value of "map" reference is real object created in heap. 
As "map" reference is final, it can not have any other value in it. 

When we pass "map" reference, Actually we pass the value of map which is nothing but reference of object created in heap. In the called method, another 
reference "map" will be created in stack which holds the same reference of object in heap. 

The same concept is coded in this example 

импорт java.util.HashMap; импорт java.util.Карта;

общественного класса FinalExample { государственной статической силы основных (String []) {арг

// Please see this example in case of normal variable and go through the 
    // comment 
    Final1 f1 = new Final1(); 
    f1.fun2(); 

    // Please see this example in case of Map Object and go through the 
    // comment 
    Final2 f2 = new Final2(); 
    f2.fun2(); 

} 

}

класс Final1 { конечная Int А = 10;

void fun1(int a) { 
    a += 20; 
    System.out.println(a); 
} 

void fun2() { 

    // Here we are passing just content of final variable "a" but not the 
    // block "a" itself. 

    // When method fun1 is called another local block "a" will be created 
    // This local "a" has nothing to do with instance final "a". Both are 
    // different 
    // We can change the value of local a it has nothing to do with instance 
    // "a" 

    fun1(a); 
} 

}

класса Final2 { конечная статическая Карта Карты = новый HashMap();

static { 
    map.put("1", "Nandeshwar"); 
    map.put("2", "Sah"); 
} 

void fun1(Map map) { 
    map.put("3", "John"); 
    map.put("4", "Nash"); 

    System.out.println(map); 
} 

void fun2() { 

    // Here (in fun1) we pass the content of final map. The content of final 
    // map is 
    // the refernece of real object which holds the value 
    // "1" "Nandeshwar // "2" "Sah". 

    // When we call fun1, Another object "map(Map)" will be created. this 
    // newly created object "map" will also 
    // indicate the same reference as instance map refers 

    // So the local object "map" and instance object "map" both is 
    // different. But indicates the real Object which holds the value 
    fun1(map); 
} 

}

+3

Простой код - это не ответ. Вы должны объяснить. – EJP

2

Как уточнили другие ответы, вы не можете сделать окончательный Переменная см другому объекту.

Цитируя Java Language Specification:

4.12.4. конечные переменные

Конечная переменная может быть назначена только один раз ... Если конечная переменная содержит ссылку на объект, тогда состояние объекта может быть изменено с помощью операций над объектом, но переменная всегда будет обратитесь к одному и тому же объекту.

Это правило не нарушается в редактируемой части вашего вопроса:

  • вы объявили CacheMap как окончательный, и вы не переназначение новое значение к нему в любом месте. Если вы сможете это сделать, это будет нарушение .

  • cachemapdeclaredasfinal только относится то же самое, что CacheMap является со ссылкой, и является не окончательных сам по себе.

Как Суреш упомянул upthread, это поможет, если вы прочитаете значения и ссылки на Java. Хорошей отправной точкой является эта тема: Is Java "pass by reference"?. Удостоверьтесь, что вы понимаете, почему Java всегда имеет значение pass-by-value и never pass-by-reference - вот почему «окончательность» CacheMap не проходила мимо.

0

точки "C/C++":

Thing * a; 
Thing * const b; 
Thing const * c; 
Thing const * const d; 

"окончательного" в Java ближе всего к "б". «b» - постоянный указатель на Вещь. «b» нельзя изменить, чтобы указать на другую вещь, но сама вещь может быть изменена.

Java не имеет представления для «c» и «d». «c» - указатель на постоянную вещь. «c» может указывать на другие вещи, но значения, на которые он указывает, не могут быть изменены (по крайней мере, не через «c»)

«d» объединяет «b» и «c»: «d» является постоянный указатель на константу Thing.

О, и «а», конечно, просто ничего особенного.

Hm ... В Java не все является объектом, поэтому правила немного отличаются.

final int f = 9; 

Который, в C очень похож

int const f = 9; 

Что означает, что вы не можете изменить "F" или его целочисленное значение.

Примечание:

int const f; 
const int g; 

оба означают то же самое, но "е" ИМХО имеет четкое значение. "g", к сожалению, очень распространено.

3

Я думаю, вы получаете путать между «конечными» и «неизменными» объектами ..

public class Final { 

    private final int b; 

    Final(int b) { 
      this.b = b; 
    } 

    int getFinal() { 
      return b = 8; // COMPILE TIME ERROR 
    } 
} 

Final означает, что вы не можете изменить ссылку на объект. В случае примитивов это означает, что вы не можете изменить значение. Итак, когда вы пытаетесь установить b на 8, вы получаете ошибку времени компиляции.

cc.setConditionMap(cacheMap); 

public void setConditionMap(Map conditionMap) { 
     this.conditionMap = conditionMap; 
} 

В Java - «Ссылки на объекты передаются по значению» (как Брюс Eckel ставит его в своей книге «Мышление в Java»). Итак, вы передаете копию справки. Итак, теперь у вас есть 2 ссылки на одну и ту же кеш-карту.

Итак, вы можете изменить cacheMap, используя любую из ссылок. Но вы можете переназначить только «скопированную» ссылку на другой объект, поскольку он не является окончательным (а не оригинальным, исходный является окончательным и НЕ МОЖЕТ указывать на другой объект).

0

Это те Обычаи ключевое слово окончательное, что я знаю:

В объявлении класса

Это означает, что класс: не может быть суб классифицироваться

public final class SomeClass { 
//... 
} 

В глобальная переменная

Это означает, что после того, как значение будет assi он не может измениться.

public class SomeClass { 
    private final int value = 5; 
} 

Там будет ошибка компиляции, если не присвоить значение, но то, что вы можете сделать, это использовать состав, чтобы дать значение.

public class SomeClass { 
    private final int value; 
    public SomeClass(int value) { 
     this.value=value 
     } 
} 

В параметре объекта

Это означает, что переданный объект не может быть изменен

public class SomeClass { 
    public void someMethod(final String value) { 
     //... 
    } 
} 

В локальных переменных

Это означает, что значение не может изменить один раз присвоено

public class SomeClass { 
    public void someMethod(final String value) { 
     final double pi = 3.14; 
    } 
} 

В методах

Это означает, что метод не может быть переопределен

public class SomeClass { 
      public final void someMethod() { 
       //... 
      } 
     } 

В коллекции & карты

Это означает, что коллекция не может быть повторно инициализирован, но это не означает, что элементы являются inmutable, каждый из элементов не будет afected по ключевому слову final

public class SomeClass { 
     final HashMap<K, V> someMap = new HashMap<K, V>(); 
    } 
0

Если ссылка является окончательным, оно не может быть связан с любым другим объектом.

Значения объекта могут быть изменены, поэтому вы можете добавлять значения к карте, но не можете изменить объект карты.

-1

Примечание: - Когда вы объявляете ссылку на объект в качестве окончательной, это означает, что она всегда будет указывать на тот же объект в куче, который был инициализирован.

Если cacheMap который объявлен как окончательный передается в качестве параметра другой класс, то ошибка не показан для окончательного если я изменить его ссылку. Почему это так?

1.) Java является передача по значению так, когда вы пишете cc.setConditionMap(cacheMap), где cacheMap является ссылкой на объект (Примечание: - cacheMap не является сам объект, это просто ссылка), то вы просто передавая адрес объекта в куче до setConditionMap(cacheMap), теперь внутри setConditionMap(cacheMap), conditionMap инициализируется значением cacheMap (значение кэш-карты - это адрес объекта карты). Теперь после этого этапа оба conditionMap и cacheMap относятся к одному и тому же объекту в куче. Но уловка в том, что вы можете снова установить значение conditionMap, чтобы он указывал на какой-либо другой объект карты в куче, но cacheMap всегда будет указывать на тот же объект карты.

2.) Объявление переменной как final не означает, что объект в куче является окончательным (не имеет смысла вообще, правильно?), А не то, что это означает, состоит в том, что переменная всегда будет указывать на объект, к которому он был инициализирован, и никто не может его изменить.

Смежные вопросы