Почему я должен использовать ключевое слово "final" для параметра метода в Java? - PullRequest
354 голосов
/ 01 февраля 2009

Я не могу понять, где ключевое слово final действительно удобно, когда оно используется в параметрах метода.

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

Обеспечение того, что некоторые данные остаются постоянными, не так сильно, как кажется.

  • Если параметр является примитивом, то он не будет иметь никакого эффекта, поскольку параметр передается методу в качестве значения, и его изменение не окажет никакого влияния вне области действия.

  • Если мы передаем параметр по ссылке, то сама ссылка является локальной переменной, и если ссылка изменяется внутри метода, это не будет иметь никакого влияния вне области метода.

Рассмотрим простой пример теста ниже. Этот тест проходит, хотя метод изменил значение заданной ссылки, но не имеет никакого эффекта.

public void testNullify() {
    Collection<Integer> c  = new ArrayList<Integer>();      
    nullify(c);
    assertNotNull(c);       
    final Collection<Integer> c1 = c;
    assertTrue(c1.equals(c));
    change(c);
    assertTrue(c1.equals(c));
}

private void change(Collection<Integer> c) {
    c = new ArrayList<Integer>();
}

public void nullify(Collection<?> t) {
    t = null;
}

Ответы [ 12 ]

0 голосов
/ 17 марта 2016

Следите за тем, что написал Мишель. Я сам сделал другой пример, чтобы объяснить это. Я надеюсь, что это может помочь.

public static void main(String[] args){
    MyParam myParam = thisIsWhy(new MyObj());
    myParam.setArgNewName();

    System.out.println(myParam.showObjName());
}

public static MyParam thisIsWhy(final MyObj obj){
    MyParam myParam = new MyParam() {
        @Override
        public void setArgNewName() {
            obj.name = "afterSet";
        }

        @Override
        public String showObjName(){
            return obj.name;
        }
    };

    return myParam;
}

public static class MyObj{
    String name = "beforeSet";
    public MyObj() {
    }
}

public abstract static class MyParam{
    public abstract void setArgNewName();
    public abstract String showObjName();
}

Из приведенного выше кода в методе thisIsWhy () мы фактически не присваиваем [аргумент MyObj obj] для реальная ссылка в MyParam. Вместо этого мы просто используем [аргумент MyObj obj] в методе внутри MyParam.

Но после того, как мы закончим метод thisIsWhy () , должен ли еще существовать аргумент (объект) MyObj?

Похоже, что так и должно быть, потому что мы можем видеть в основном, что мы все еще вызываем метод showObjName () , и ему нужно достичь obj . MyParam по-прежнему использует / достигает аргумента метода, даже если метод уже был возвращен!

Как на самом деле Java это делает - это создание копии также является скрытой ссылкой аргумента MyObj obj внутри объекта MyParam (но это не формальное поле в MyParam, поэтому мы не можем его увидеть )

Поскольку мы называем "showObjName", он будет использовать эту ссылку для получения соответствующего значения.

Но если мы не поставили окончательный аргумент, что приводит к ситуации, мы можем переназначить новую память (объект) на аргумент MyObj obj .

Технически нет никакого столкновения вообще! Если нам позволят это сделать, ниже будет ситуация:

  1. Теперь у нас есть скрытая точка [MyObj obj] для объекта [Memory A in heap], который теперь находится в объекте MyParam.
  2. У нас также есть еще один [MyObj obj], который является аргументом для [Памяти B в куче], теперь живущей в методе thisIsWhy.

Никаких противоречий, но "ЗАМЕДЛЕННЫЙ !!" Поскольку все они используют одно и то же "ссылочное имя", которое "obj" .

Чтобы избежать этого, установите его как «окончательный», чтобы программист не делал «подверженный ошибкам» код.

0 голосов
/ 02 февраля 2009

Еще одна причина добавить final к объявлениям параметров состоит в том, что это помогает идентифицировать переменные, которые должны быть переименованы как часть рефакторинга «Extract Method». Я обнаружил, что добавление final к каждому параметру перед началом большого рефакторинга метода быстро говорит мне, есть ли какие-либо проблемы, которые мне нужно решить перед продолжением.

Однако я обычно удаляю их как лишние в конце рефакторинга.

...