Заключительные аргументы в интерфейсных методах - какой смысл? - PullRequest
181 голосов
/ 21 марта 2011

В 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 для параметров метода интерфейса?

Ответы [ 5 ]

95 голосов
/ 21 марта 2011

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

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

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

23 голосов
/ 21 марта 2011

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

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

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

17 голосов
/ 21 марта 2011

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

6 голосов
/ 02 июля 2013

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

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

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

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

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


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

Объекты:

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, где мы потеряли цветную капусту, потому что она добавила это в новый местный кастрюлю вместо оригинального кастрюли, которую он получил.

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

2 голосов
/ 21 марта 2011

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

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

...