О локальных конечных переменных в Java - PullRequest
2 голосов
/ 10 июня 2010

В Java-программе, параметры которой определены как String в объявлении метода. Но в определении метода он доступен как переменная final String. Приведет ли это к некоторым проблемам (таким как безопасность, проблема с памятью)?

Например:

Декларация метода

join(String a,String b);

Определение метода

public void join(final String a,final String b)
{
    Authenticator au = new Authenticator(){
        public PasswordAuthentication getPasswordAuthentication(){
        return new PasswordAuthentication(a,b)}
    };
}

Пожалуйста, помогите мне и проясните мои сомнения. Заранее спасибо

P.S. Я обращаюсь к a и b как к окончательной переменной, потому что я должен использовать ее во внутреннем классе.

Ответы [ 4 ]

18 голосов
/ 10 июня 2010

final просто означает, что переменной / примитиву не может быть присвоено новое значение. Это не то же самое, что const концепция (которой нет в Java); НЕ гарантирует неизменность. String в Java, конечно, уже достаточно неизменен (за исключением неприятных атак отражением).

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

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

JLS 14.2.4 final Переменные

Переменная может быть объявлена ​​final. Переменная final может быть назначена только один раз. Это ошибка времени компиляции, если назначена переменная final, если только она не была определенно назначена непосредственно перед назначением.

Как уже упоминалось, однако, final само по себе не гарантирует неизменности объекта, на который ссылаются. Объявление final StringBuilder sb гарантирует, что sb, однажды назначенный и находящийся в пределах его области действия, не будет ссылаться на другой экземпляр StringBuilder. StringBuilder Сам, конечно, изменчивый объект.


final и внутренние классы

Другое использование модификатора final - разрешить использование локальных переменных и т. Д. Внутренним классом:

JLS 8.1.3 Внутренние классы и вложенные экземпляры

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

Это связано с тем, как внутренние классы, использующие эти переменные, компилируются в Java, деталь реализации, которая, возможно, не слишком важна для обсуждения. По сути, значения этих final переменных передаются внутренним классам во время построения. Последующие изменения локальных переменных (если они разрешены) не будут видны внутреннему экземпляру класса. Для обеспечения правильной семантики эти локальные переменные должны быть объявлены final.


Эффекты модификатора final для локальных переменных во время выполнения

Модификатор

final для локальных переменных / параметров формального метода является концепцией времени компиляции и не присутствует, скажем, на уровне байт-кода (то есть он играет совсем другую роль, чем модификатор final для полей, классов и методы). Таким образом, эта концепция просто не существует во время выполнения, где final и не- final локальные переменные неразличимы; использование самого ключевого слова не повлияет на сбор и / или сборку мусора.

Возможность сбора мусора определяется с точки зрения наличия или отсутствия живых ссылок на объект. Локальные переменные и аргументы метода выходят из области видимости в конце метода (или блока, в котором они объявлены), независимо от того, объявлены они или нет final. Выход за рамки означает, что ссылка "мертвая". Сам объект может иметь живые ссылки из других источников.

В этом конкретном случае формальные параметры метода объявляются final, чтобы их можно было использовать во внутреннем классе. Как упоминалось выше, внутренний класс будет копировать эти ссылки для собственного использования. Таким образом, в данном конкретном случае объект Authenticator будет иметь ссылки на объекты String, на которые ссылаются a и b.

Проще говоря, чем больше ссылок на объект, тем сложнее его квалифицировать как мусор, неразборчивый для сбора. Однако основным фактором является живучесть этих ссылок, а не то, являются ли они final.


При профилировании

Хорошо понимать концепции, чтобы снять любые сомнения по поводу использования памяти / проблем с производительностью;лучше просто профилировать и посмотреть, являются ли проблемы реальными, и исправить их по мере необходимости.Хорошо спроектированная система должна быть легко адаптируемой к такого рода изменениям.

3 голосов
/ 10 июня 2010

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

0 голосов
/ 10 июня 2010

Создание переменных final не имеет ничего общего с безопасностью или распределением памяти.Это не влияет на безопасность и использование памяти.

0 голосов
/ 10 июня 2010

Добавление final не меняет подпись и не создает никаких других проблем. Таким образом, можно использовать метод, указанный интерфейсом (например). Это имеет значение только для кода внутри метода.

...