JavaRush /Java блог /Архив info.javarush /Методы и классы final Java
articles
15 уровень

Методы и классы final Java

Статья из группы Архив info.javarush
Обозначая метод класса модификатором final, мы имеем ввиду, что ни один производный класс не в состоянии переопределить этот метод, изменив его внутреннюю реализацию. Другими словами, речь идет о финальной версии метода. Класс в целом также может быть помечен как final. Методы и классы final Java - 1

final class NoExtending {
// …
}
Класс, помеченный как final, не поддается наследованию и все его методы косвенным образом приобретают свойство final. Применение признак а final в объявлениях классов и методов способно повысить уровень безопасности кода. Если класс снабжен модификатором final, никто не в Состоянии расширить класс и, вероятно, нарушить при этом его контракт. Если признаком final обозначен метод, вы можете полностью доверять его внутренней реализации во всех ситуациях, не опасаясь "подделки". Уместно применить final, например, в объявлении метода, предусматривающего проверку пароля, вводимого пользователем, чтобы гарантировать точное Исполнение того, что методом предусмотрено изначально. Возможному злоумышленнику не удастся изменить исходную реализацию такого метода, "подсунув" программе его переопределенную версию, которая, скажем, всегда возвращает значение true, свидетельствующее об успешной регистрации пользователя, независимо от того, какой пароль он ввел на самом деле. Вы вправе, если позволяет конкретная ситуация, пойти дальше и объявить как final класс целиком; метод ValidatePassword приобретёт то же свойство косвенным путём. Употребление модификатора final в объявлении метода или класса накладывает серьезные ограничения на возможность дальнейшего использования и развития кода. Применение final в объявлении метода – это верный показатель того, что реализация метода самодостаточна и полностью завершена. Другие программисты, которые захотят воспользоваться вашим классом, расширив его функции в угоду собственным потребностям, будут стеснены в выборе средств достижения цели либо полностью лишены таковых. Пометив признаком final класс в целом, вы запретите возможность его наследования и, вероятно, существенно снизите его практическую ценность для других. Собравшись применить модификатор final, убедитесь, готовы ли ВЫ к подобным жертвам и стоит ли их принести. Во многих случаях для достижения достаточного уровня безопасности кода вовсе нет необходимости обозначать весь класс как final – вполне возможно сохранить способность класса к расширению, пометив модификатором final только его "критические" структурные элементы. В этом случае вы оставите в неприкосновенности основные функции класса и одновременно разрешите его наследование с добавлением новых членов, но без переопределения "старых". Разумеется, поля, к которым обращается код методов final, должны быть в свою очередь обозначены как final либо private, поскольку в противном случае любой производный класс получит возможность изменять их содержимое, воздействуя на поведение соответствующих методов. Еще один эффект применения модификатора final связан с упрощением задачи оптимизации кода, решаемой компилятором. Вот что происходит, когда вызывается метод, не помеченный как final, исполняющая система определяет фактический класс объекта, связывает вызов с наиболее подходящим кодом из группы перегруженных методов и передает управление этому коду. Но если бы, например, метод getName в примере класса Attr, рассмотренном раньше, был обозначен как final, операция обращения к нему, возможно, была бы заметно упрощена. В самом тривиальном случае, подобном тому, который касается getName, компилятор может попросту заменить вызов метода кодом его тела. Такой механизм носит название встраивания кода (inlining). При использовании inline-версии метода getName два следующих выражения выполняются совершенно одинаково:

system.out.println("id = " + rose.name);
system.out.println("id = " + rose.getName());
Хотя приведенные выражения равнозначны, второе все-таки обладает преимуществом, поскольку метод getName позволяет придать полю name свойство "только для чтения", а коду класса – некую степень абстракции, которая обеспечивает возможность более свободного изменения реализации класса. Та же схема оптимизации может быть применена компилятором и по отношению к методам private и statiс, так как и они не допускают переопределения. Использование модификатора final в объявлениях классов способствует также повышению эффективности некоторых операций проверки типов. В этом случае многие подобные операции могут быть выполнены уже на стадии компиляции и поэтому потенциальные ошибки выявляются гораздо раньше. Если компилятор встречает в исходном тексте ссылку на класс final, он может быть "уверен", что соответствующий объект относится именно к тому типу, который указан. Компилятор в состоянии сразу определить место, занимаемое классом в общей иерархии классов, и проверить, верно тот используется или нет. Если модификатор final не применяется, соответствующие проверки осуществляются только на стадии выполнения программы. Упражнение 3.4. Целесообразно ли включить в объявления методов (и если да, та каких именно) классов vehicle и passengervehicle модификатор final? Ссылка на первоисточник: http://src-code.net/metody-i-klassy-final-java
Комментарии (2)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
🦔 Виктор Уровень 20 Expert
4 марта 2023
Ужасный машинный перевод.
MaxST1994 Уровень 12
27 марта 2016
Надо отметить что final очень важный модификатор для аргументов, если мы подаем аргументы для метода, то подразумевается, что аргументы эти подаются на чтение.
Так как они уничтожатся после выполнения метода все равно, слышал что правилом хорошего тона считается помечать эти аргументы в сигнатуре метода модификатором final

то есть например для setter
public void setNum(int x){}

настоятельно рекомендуется (но не обязательно) писать
public void setNum(final int x)
{
    this.x = x;
}

Почему рекомендуется?
Мы можем назвать аргумент, к примеру, сеттера не одноименно полю класса, а иначе и написать
public int setNum(int argx)
{
    x = argx;
}

но это опять же считается не очень хорошей формой записи, желательно this.x = argx; this показывает что мы выполняем действия именно с полем класса
или например
public int multipleX(int argx) //множим х на аргх 
{
    argx*=x;
    return argx;
}

Тоже запись плохого тона
И вот чтобы таких косячков не было пишем
final
. Тогда аргумент на чтение нельзя будет изменить

public int multipleX(final int argx) //множим х на аргх 
{
    this.x*= argx;
    return this.x;
}