Последнее ключевое слово в параметрах метода
Я часто сталкиваюсь с методами, которые выглядят следующим образом:
public void foo(final String a, final int[] b, final Object1 c){
}
Что происходит, если этот метод вызывается без передачи ему окончательных параметров. то есть Object1, который позже изменен (поэтому не объявлен как final), может быть просто передан этому методу
10 ответов
Java всегда делает копию параметров перед отправкой их в методы. Это означает, что финал не означает никакой разницы для вызывающего кода. Это означает только то, что внутри метода переменные не могут быть переназначены. (обратите внимание, что если у вас есть конечный объект, вы все равно можете изменить атрибуты объекта).
Существует обстоятельство, когда вам необходимо объявить его окончательно - иначе это приведет к ошибке компиляции - а именно, передать их в анонимные классы. Основной пример:
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
модификатор приведет к ошибке компиляции, потому что больше не гарантируется, что значение является константой времени выполнения. Изменение значения вне анонимного класса может привести к тому, что экземпляр анонимного класса будет вести себя по-другому после момента создания.
Java является только передачей по значению. (или лучше - передача по ссылке по значению)
Таким образом, переданный аргумент и аргумент в методе - это два разных обработчика, указывающих на один и тот же объект (значение).
Поэтому, если вы изменяете состояние объекта, оно отражается на каждой другой переменной, которая на него ссылается. Но если вы переназначаете новый объект (значение) для аргумента, то другие переменные, указывающие на этот объект (значение), не будут переназначены.
final
Ключевое слово в параметре метода абсолютно ничего не значит для вызывающей стороны. Это также абсолютно ничего не значит для работающей программы, поскольку ее наличие или отсутствие не изменяет байт-код. Это только гарантирует, что компилятор будет жаловаться, если переменная параметра переназначена в методе. Это все. Но этого достаточно.
Некоторые программисты (как и я) думают, что это очень хорошо, и используют final
почти по каждому параметру. Это облегчает понимание длинного или сложного метода (хотя можно утверждать, что длинные и сложные методы должны подвергаться рефакторингу.) Это также проливает свет на параметры метода, которые не отмечены final
,
Рассмотрим эту реализацию foo():
public void foo(final String a) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
System.out.print(a);
}
});
}
Поскольку Runnable
экземпляр переживет метод, он не будет компилироваться без final
ключевое слово - final
говорит компилятору, что можно безопасно взять копию ссылки (чтобы обратиться к ней позже). Таким образом, ссылка считается окончательной, а не значение. Другими словами: как абонент, вы ничего не можете испортить...
Если вы объявите какой-либо параметр как окончательный, вы не сможете изменить его значение.
class Bike11 {
int cube(final int n) {
n=n+2;//can't be changed as n is final
n*n*n;
}
public static void main(String args[]) {
Bike11 b=new Bike11();
b.cube(5);
}
}
Вывод: ошибка времени компиляции
Для получения более подробной информации, пожалуйста, посетите мой блог: http://javabyroopam.blogspot.com/
final означает, что вы не можете изменить значение этой переменной после ее назначения.
Между тем, использование final для аргументов в этих методах означает, что он не позволит программисту изменять их значение во время выполнения метода. Это только означает, что внутри метода конечные переменные не могут быть переназначены.
Ключевое слово final во входном параметре метода не требуется. Java создает копию ссылки на объект, поэтому добавление final не делает объект final, а просто ссылкой, что не имеет смысла
Строки являются неизменяемыми, поэтому на самом деле вы не можете впоследствии изменить String (вы можете только сделать, чтобы переменная, которая содержала объект String, указывала на другой объект String).
Однако это не причина, по которой вы можете связать любую переменную с final
параметр. Все проверки компилятора состоят в том, что параметр не переназначается в методе. Это хорошо для целей документирования, возможно, хорошего стиля, и может даже помочь оптимизировать байт-код для скорости (хотя на практике это не очень помогает).
Но даже если вы переназначаете параметр в методе, вызывающая сторона этого не замечает, потому что java выполняет передачу всех параметров по значению. После последовательности
a = someObject();
process(a);
поля a, возможно, изменились, но объект по-прежнему тот же, что и раньше. В языках передачи по ссылке это может быть не так.
@stuXnet, я мог бы привести совершенно противоположный аргумент. Если вы передаете объект в функцию и изменяете свойства переданного объекта, то вызывающая функция будет видеть измененное значение в своей переменной. Это подразумевает передачу по ссылочной системе, а не по значению.
Что сбивает с толку, так это определение передачи по значению или передачи по ссылке в системе, где использование указателей полностью скрыто для конечного пользователя.
Java определенно НЕ передается по значению, так как это может означать, что можно переделать переданный объект, и оригинал не будет затронут.
Обратите внимание, что вы не можете изменять примитивы, вы можете назначать их только переменным. Поэтому тестирование Pass по ссылке или по значению с использованием примитивов не является тестом.
То, что вы не можете сделать в Java, что можно сделать в других языках, - это переназначить переменные вызывающей стороны на новое значение, потому что в Java нет указателей, поэтому это может сбить с толку.
Почти все было сказано о final
параметры метода в Java
; но я хотел бы добавить крошечную простую вещь, что вы можете думать об этом final
параметр метода как const
параметры передачи по ссылке в C++
как =>
void someMethod(const int* param1)
{
...
}