Окончательные аргументы в методах интерфейса - какая точка?

В Java вполне логично определять аргументы final в методах интерфейса и не подчиняться этому в классе реализации, например:

public interface Foo {
    public void foo(int bar, final int baz);
}

public class FooImpl implements Foo {

    @Override
    public void foo(final int bar, int baz) {
        ...
    }
}

В приведенном выше примере bar и baz имеют противоположные определения final в классе VS интерфейса.

Таким же образом, ограничения final не применяются, когда один метод класса расширяет другой, либо abstract, либо нет.

Хотя final имеет практическое значение внутри тела метода класса, существует ли какая-либо точка, указывающая final для параметров интерфейса интерфейса?

Ответ 1

Похоже, в этом нет никакого смысла. Согласно спецификации языка Java 4.12.4:

Объявление переменной final может служить полезной документацией, что ее значение не изменится и поможет избежать ошибок программирования.

Однако final модификатор параметра метода не упоминается в правилах сопоставления подписей переопределенных методов, и он не влияет на вызывающую функцию, только в теле реализации. Кроме того, как отметил Робин в комментарии, final модификатор параметра метода не влияет на сгенерированный байт-код. (Это не относится к другим видам использования final.)

Ответ 2

Некоторые IDE будут копировать сигнатуру абстрактного/интерфейсного метода при вставке реализующего метода в подкласс.

Я не верю, что это имеет какое-либо значение для компилятора.

РЕДАКТИРОВАТЬ: Хотя я считаю, что это было правдой в прошлом, я не думаю, что текущие IDE делают это больше.

Ответ 3

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

Ответ 4

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

Что касается вопроса, я хотел бы привести свой собственный комментарий ниже.

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

Но да, это звучит довольно странно, что вы можете объявить его final в интерфейсе, но при этом он не является окончательным в реализации. Это имело бы смысл, если бы:

Ключевое слово

a. final не разрешено для интерфейсных (абстрактных) аргументов метода (но вы можете использовать его в реализации) или
b. объявление аргумента как final в интерфейсе заставит его объявить final в реализации (но не принудительно для нефиналов).


Я могу представить две причины, по которым сигнатура метода может иметь параметры final: Beans и Объекты (На самом деле, они являются одной и той же причиной, но несколько разных контекстов.)

Объекты:

public static void main(String[] args) {
    StringBuilder cookingPot = new StringBuilder("Water ");
    addVegetables(cookingPot);
    addChicken(cookingPot);
    System.out.println(cookingPot.toString());
    // ^--- OUTPUT IS: Water Carrot Broccoli Chicken ChickenBroth 
    //      We forgot to add cauliflower. It went into the wrong pot.
}

private static void addVegetables(StringBuilder cookingPot) {
    cookingPot.append("Carrot ");
    cookingPot.append("Broccoli ");
    cookingPot = new StringBuilder(cookingPot.toString());
    //   ^--- Assignment allowed...
    cookingPot.append("Cauliflower ");
}

private static void addChicken(final StringBuilder cookingPot) {
    cookingPot.append("Chicken ");
    //cookingPot = new StringBuilder(cookingPot.toString());
    //     ^---- COMPILATION ERROR! It is final.
    cookingPot.append("ChickenBroth ");
}

Ключевое слово final гарантировало, что мы случайно не создадим новый локальный кулинарный горшок, показывая ошибку компиляции, когда мы попытаемся это сделать. Это обеспечило добавление куриного бульона в наш оригинальный горшок для приготовления пищи, который получил метод addChicken. Сравните это с addVegetables, где мы потеряли цветную капусту, потому что она добавила, что в новый локальный кулинарный горшок вместо исходного банка, который он получил.

Beans: Это та же концепция, что и объекты (как показано выше). Beans по существу Object в Java. Однако Beans (JavaBeans) используются в различных приложениях как удобный способ хранения и передачи определенного набора связанных данных. Так же, как addVegetables может испортить процесс приготовления пищи, создав новый кухонный горшок StringBuilder и выбросив его с помощью цветной капусты, он также может сделать то же самое с кулинарным вареном JavaBean.

Ответ 5

Я считаю, что это может быть излишняя деталь, так как окончательный или нет - деталь реализации.

(похоже, как объявление методов/членов в интерфейсе как общедоступное.)