Почему переменная класса final экземпляра в Java?

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

public class Final {

    private final int b;

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

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


Где-то в коде я видел переменную класса экземпляра HashMap, объявленную как final

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

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

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

 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.

Ответы

Ответ 1

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

От Спецификация языка # глава 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());

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

Изменить 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 дальше.

Короче

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

Ответ 2

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

Ответ 3

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

public class Final {

     private final int b;

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

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

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

cc.setConditionMap(cacheMap);

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

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

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

Ответ 4

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

Цитата из Спецификация языка Java:

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

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

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

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

  • cachemapdeclaredasfinal относится только к тому, что CacheMap ссылаясь на, и не является окончательным.

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

Ответ 5

Это означает, что 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
}

Ответ 6

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

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

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

Ответ 7

В терминах "C/С++":

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

"final" в Java ближе всего к "b". "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;

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

Ответ 8

Это слова ключевого слова final, которые я знаю:

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

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

public final class SomeClass {
//...
}

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

Это означает, что после присвоения ему значения он не может измениться.

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, каждый элемент не будет зависеть от ключевого слова final

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

Ответ 9

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

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

Ответ 10

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

Ссылка

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

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; import java.util.Map;

открытый класс FinalExample {   public static void main (String [] args) {

    // 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();

}

}

class Final1 {   final int a = 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 {   окончательная статическая карта map = new 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);
}

}

Ответ 11

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

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

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

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