Заключні аргументи в інтерфейсних методах - в чому сенс?


189

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


finalтак чи інакше нічого не роблять із рідними типами, оскільки вони скопійовані.
Пол Томблін

11
Тільки як пункт дискусії: я тільки що спробував це, і якщо два interfaceвизначення відрізняються лише в finalатрибуті аргументу, то отримані .classфайли є байтом-байтом однаково (і, звичайно, javap -vвидає однаковий результат). Те саме стосується двох класів, які відрізняються лише finalза атрибутом, до речі!
Йоахім Зауер

2
@Paul: це робить точно так само, як і для посилальних типів: запобігає зміні самих аргументів (якщо вони використовуються в реалізації).
Йоахім Зауер

Він має стільки ж актуальності, скільки громадськість у підписі методу.
Робін

2
@Deepak: Я бачу, що ви ставите робочі приклади на всілякі питання, навіть коли це, здається, не має великого сенсу. Я думаю, вам слід спробувати навчитися деякому абстрактному мисленню: спробуйте подумати про проблему, не маючи перед собою якийсь виконуваний код. Це дуже допоможе вам у довгостроковій перспективі.
Йоахім Зауер

Відповіді:


104

Здається, це не має жодного сенсу. Відповідно до специфікації мови Java 4.12.4 :

Оголошення змінної остаточним може послужити корисною документацією, що її значення не зміниться і може допомогти уникнути помилок програмування.

Однак finalмодифікатор параметра параметру методу не згадується в правилах узгодження підписів замінених методів, і він не впливає на абонента, лише в тілі програми реалізації. Також, як зазначив Робін у коментарі, finalмодифікатор параметра методу не впливає на сформований код байта. (Це не стосується інших цілей використання final.)


Чи кваліфікується також параметр методу як змінної? Це, очевидно, є на практиці, але чи є це в специфікаційному контексті?
mindas

11
Його не можна використовувати для співпадіння підписів, оскільки він не відображається у фактичному файлі .class. Це лише для компілятора.
Робін

@mindas - JLS говорить, що існує сім видів змінних . Параметри методу займають четверте місце в списку.
Тед Хопп

3
Однак документація поруч із марною, оскільки finalмодифікатор не застосовується до класу реалізації. Ваш підпис інтерфейсу може просто лежати.
Стефан Хаберл

Спеціалізація мови Java 8 тепер говорить, що існує вісім видів змінних (до семи - вони додали лямбда-параметри ). Параметри методу все ще четверті у списку (принаймні деякі речі в житті здаються стабільними. :-)).
Тед Хопп

25

Деякі IDE копіюють підпис методу абстрактно / інтерфейсу під час вставлення способу реалізації у підклас.

Я не вірю, що це має значення для компілятора.

EDIT: Хоча я вважаю, що це було правдою в минулому, я не думаю, що нинішні ІДЕ вже роблять це.


2
Дійсна точка, хоча я не думаю, що було багато ідентифікаторів, коли ця функція була реалізована (або залишилась випадково) :-)
mindas

2
Я думаю, що в категорії static transientполів. ;)
Пітер Лорі

1
І громадські конструктори на абстрактному класі.
Пітер Лорі

1
IntelliJ робить це. Моя версія - IntelliJ IDEA 2016.1.3 Build # IU-145.1617.
Dormouse

1
@Dormouse, це цікаво, адже Android Studio (3.1.4 Build # AI-173.4907809) не робить :(
Хрещений батько

18

Підсумкові анотації параметрів методу завжди стосуються лише реалізації способу, а ніколи абоненту. Тому немає реальної причини використовувати їх у підписах методів інтерфейсу. Якщо ви не хочете дотримуватися того самого послідовного стандарту кодування, який вимагає остаточних параметрів методу, у всіх підписах методу. Тоді приємно вміти це робити.


6

Оновлення: Оригінальна відповідь нижче була написана без повного розуміння питання, а тому не стосується безпосередньо питання. :)Тим не менш, вона повинна бути інформативною для тих, хто хоче зрозуміти загальне використання finalключового слова.

Щодо питання, я хотів би процитувати власний коментар знизу.

Я вважаю, що ви не змушені застосовувати остаточний аргумент, щоб ви могли вирішити, чи він повинен бути остаточним чи ні у вашій власній реалізації.

Але так, це здається дивним, що ви можете оголосити це finalв інтерфейсі, але мати його не остаточним у реалізації. Було б більше сенсу, якби:

а. finalключове слово не було дозволено для аргументів методу інтерфейсу (абстрактних) (але ви можете використовувати його в реалізації), або
b. Оголошення аргументу як finalінтерфейсу змусило б його оголосити finalу впровадженні (але не вимушено для нефіналу).


Я можу подумати про дві причини, за якими підпис методу може мати finalпараметри: Beans and 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. Однак квасоля (JavaBeans) використовується в різних додатках як зручний спосіб зберігання та передачі певного збору пов'язаних даних. Так само, як addVegetablesміг зіпсувати процес приготування, створивши новий котел для готування StringBuilderі викинувши його з цвітною капустою, він також міг би зробити те ж саме з варом для готування JavaBean .


Гаразд. Це не дуже правильна відповідь на питання, (оскільки я не змушений змушувати реалізацію методу інтерфейсу брати остаточні аргументи, навіть якщо інтерфейс так говорить), але це все-таки корисно, оскільки це приємне пояснення того, чому зробити параметри методу остаточними - це хороша ідея для початку.
Філ

Я вважаю, що ви не змушені застосовувати остаточний аргумент, щоб ви могли вирішити, чи він повинен бути остаточним чи ні у вашій власній реалізації. Але так, це здається дивним, що ви можете оголосити це finalв інтерфейсі, але мати його не остаточним у реалізації. Було б більше сенсу, якби для (аргументів ) final не було дозволено ключове слово (а) для аргументів інтерфейсного (абстрактного) методу (але ви можете використовувати його в реалізації), або (б) оголошення аргументу, як finalв інтерфейсі, змусить його оголосити finalв реалізації (але не вимушений для нефіналу).
ADTC

"Це насправді не правильна відповідь на питання" Ти маєш рацію, я не знаю, про що я думав ... напевно, це були перші липні години липня чи щось таке ". :)
ADTC

2

Я вважаю, що це може бути зайвою деталлю, оскільки вона остаточна чи ні, це деталь реалізації.

(Сортують як оголошення способів / членів в інтерфейсі загальнодоступним.)

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.