Java `final` метод: что он обещает? - PullRequest
131 голосов
/ 05 апреля 2011

В классе Java метод может быть определен как final, чтобы отметить, что этот метод не может быть переопределен:

public class Thingy {
    public Thingy() { ... }
    public int operationA() {...}
    /** this method does @return That and is final. */
    public final int getThat() { ...}
}

Это понятно, и это может быть полезно для защиты от случайного переопределения или производительности & mdash; но это не мой вопрос.

У меня такой вопрос: с точки зрения ООП я понял, что, определив метод final, дизайнер классов обещает , что этот метод всегда будет работать как описано или подразумеваться. Но часто это может быть вне влияния автора класса, если то, что делает метод, является более сложным, чем просто предоставление свойства .

Синтаксические ограничения мне ясны, но каков смысл в смысле ООП? Правильно ли используется final в этом смысле большинством авторов классов?

Какой "контракт" обещает метод final?

Ответы [ 5 ]

143 голосов
/ 05 апреля 2011

Как уже упоминалось, final используется с методом Java, чтобы отметить, что метод не может быть переопределен (для области объекта) или скрыт (для статического).Это позволяет первоначальному разработчику создавать функциональные возможности, которые не могут быть изменены подклассами, и это единственная гарантия, которую он предоставляет.

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

Существует ряд причин, по которым можно что-то не настраивать, в том числе:

  • Производительность - Некоторые компиляторы могут анализировать и оптимизировать работу, особенно такую, которая не имеет побочных эффектов.

  • Получение инкапсулированных данных - посмотрите на неизменяемыеОбъекты, где их атрибуты установлены во время строительства и никогда не должны быть изменены.Или вычисленное значение, полученное из этих атрибутов.Хорошим примером является класс Java String.

  • Надежность и контракт - Объекты состоят из примитивов (int, char, double и т. д.) и / или другие объекты.Не все операции, применимые к этим компонентам, должны быть применимы или даже логичны, когда они используются в большем объекте.Для этого можно использовать методы с модификатором final.Класс Counter является хорошим примером.


public class Counter {
    private int counter = 0;

    public final int count() {
        return counter++;
    }

    public final int reset() {
        return (counter = 0);
    }
}

Если public final int count() метод не final, мы можем сделать что-то вроде этого:

Counter c = new Counter() {   
    public int count() {
        super.count();   
        return super.count();   
    } 
}

c.count(); // now count 2

или как то так:

Counter c = new Counter() {
    public int count() {
        int lastCount = 0;
        for (int i = super.count(); --i >= 0; ) {
            lastCount = super.count();
        }

        return lastCount;
    }
}

c.count(); // Now double count
23 голосов
/ 05 апреля 2011

Какой «контракт» обещает финальный метод?

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

8 голосов
/ 05 апреля 2011

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

Я согласен, что методы маркировки final не гарантируют, что их поведение будет одинаковым в подклассах, если эти методы вызывают не финальные методы.Если поведение действительно необходимо исправить, это должно быть достигнуто с помощью соглашения и тщательного проектирования.И не забудьте упомянуть это в javadoc! (Документация по java)

Последнее, но не менее важное, ключевое слово final играет очень важную роль в модели памяти Java (JMM).JMM гарантирует, что для достижения видимости final полей вам не нужна надлежащая синхронизация.Например:

class A implements Runnable {
  final String caption = "Some caption";                           

  void run() {
    // no need to synchronize here to see proper value of final field..
    System.out.println(caption);
  }
}  
0 голосов
/ 05 апреля 2011

Я не уверен, что вы можете сделать какие-либо утверждения об использовании «финала» и о том, как это влияет на общий контракт на разработку программного обеспечения.Вам гарантировано, что ни один разработчик не сможет переопределить этот метод и аннулировать свой контракт таким образом.Но с другой стороны, последний метод может полагаться на переменные класса или экземпляра, значения которых установлены подклассами, и может вызывать другие методы класса, которые переопределяются .Таким образом, окончательный вариант - это самое слабое заверение.

0 голосов
/ 05 апреля 2011

Нет, это не вне влияния автора класса.Вы не можете переопределить его в своем производном классе, поэтому он будет делать то, что задумал автор базового класса.

http://download.oracle.com/javase/tutorial/java/IandI/final.html

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

...