Java всегда делает копию параметров перед отправкой их в методы. Это означает, что final не имеет никакого значения для вызывающего кода. Это означает только то, что внутри метода переменные не могут быть переназначены. (обратите внимание, что если у вас есть конечный объект, вы все равно можете изменять его атрибуты).
Java - это только передача по значению. (или лучше - передать ссылку по значению)
Таким образом, переданный аргумент и аргумент внутри метода являются двумя разными обработчиками, указывающими на один и тот же объект (значение).
Следовательно, если вы измените состояние объекта, оно будет отражено для всех других переменных, которые на него ссылаются. Но если вы повторно назначите новый объект (значение) аргументу, то другие переменные, указывающие на этот объект (значение), не будут повторно назначены.
Рассмотрим эту реализацию foo ():
public void foo(final String a) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
System.out.print(a);
}
});
}
Поскольку экземпляр Runnable
переживет метод, он не будет компилироваться без ключевого слова final
- final
сообщает компилятору, что можно безопасно взять копию ссылки (чтобы обратиться к ней позже). Таким образом, окончательным считается эталон , а не значение . Другими словами: как вызывающий, вы не можете ничего испортить ...
Строки неизменяемы, поэтому на самом деле вы не можете изменить строку впоследствии (можно только сделать так, чтобы переменная, содержащая объект String, указывала на другой объект String).
Однако это не причина, по которой вы можете привязать любую переменную к параметру final
. Все проверки компилятора - это то, что параметр не переназначен в методе. Это хорошо для целей документации, возможно, хорошего стиля и может даже помочь оптимизировать байт-код для повышения скорости (хотя на практике это, похоже, не очень помогает).
Но даже если вы переназначаете параметр в методе, вызывающий не замечает этого, потому что java передает все параметры по значению. После последовательности
a = someObject();
process(a);
поля a могут измениться, но a по-прежнему остается тем же объектом, что и раньше. В языках с передачей по ссылке это может быть неверно.
Есть обстоятельство, при котором вы обязаны объявить его final - иначе это приведет к ошибке компиляции - а именно, передача их в анонимные классы. Основной пример:
public FileFilter createFileExtensionFilter(final String extension) {
FileFilter fileFilter = new FileFilter() {
public boolean accept(File pathname) {
return pathname.getName().endsWith(extension);
}
};
// What would happen when it's allowed to change extension here?
// extension = "foo";
return fileFilter;
}
Удаление модификатора final
приведет к ошибке компиляции, поскольку больше не гарантируется, что значение является константой времени выполнения. Изменение значения вне анонимного класса привело бы к тому, что экземпляр анонимного класса стал бы вести себя по-другому после момента создания.