Подтвердить что ты не робот

Почему частный метод может быть окончательным?

Мне интересно, почему это нормально:

class SomeClass {

    //--snip--

    private final void doStuff()
    {
        // private work here
    }
}

Если он закрыт, никто не может его переопределить, верно?

Почему возможно добавить ключевое слово final, если оно не действует? (или я что-то не хватает?)

4b9b3361

Ответ 1

В принципе, это разрешилось, потому что им не хотелось, чтобы было специальное предложение, запрещающее модификатор private. Это похоже на то, как вы также можете объявлять методы на интерфейсе как public или вложенные классы в интерфейсе как static, хотя эти ключевые слова подразумеваются в интерфейсах. Вы также можете объявить методы final в классе final и т.д.

Java взяла на себя роль не жаловаться при добавлении избыточных модификаторов. Они делают это последовательно.

Ответ 2

Это делает язык более гибким, но язык не гарантирует, что он будет иметь какой-либо эффект. Создание закрытого метода final - это подсказка к компилятору (JIT).

Спецификация языка Java отмечает, что:

Метод может быть объявлен окончательным для предотвращения переопределения или скрытия подклассов.

Ошибка компиляции, чтобы попытаться переопределить или скрыть окончательный метод.

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

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

Из Википедии:

Распространенное заблуждение состоит в том, что объявление класса или метода как окончательного повышает эффективность, позволяя компилятору напрямую вставлять метод, где бы он ни назывался (см. встроенное расширение). Но поскольку метод загружается во время выполнения, компиляторы не могут этого сделать. Только среда выполнения и компилятор JIT точно знают, какие классы были загружены, и поэтому только они могут принимать решения о том, когда inline, независимо от того, является ли этот метод окончательным

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

Ответ 3

Один краевой регистр, для которого требуется, чтобы частный метод был окончательным, используется, когда используется аннотация SafeVarargs. Следующий код не компилируется, потому что частный метод не является окончательным.

@SafeVarargs
private void method(List<String>... stringLists) {
    //TODO a safe varargs operation
}