En Java, il est parfaitement légal de définir des arguments final
dans les méthodes d'interface et de ne pas obéir à cela dans la classe d'implémentation, par exemple:
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) {
...
}
}
Dans l'exemple ci-dessus, bar
et baz
ont les définitions final
opposées dans la classe VS l'interface.
De la même manière, aucune restriction final
n'est appliquée lorsqu'une méthode de classe en étend une autre, que ce soit abstract
ou non.
Alors que final
a une valeur pratique à l'intérieur du corps de la méthode de classe, y a-t-il un point spécifiant final
pour les paramètres de la méthode d'interface?
Il ne semble pas y avoir d'intérêt. Selon la Java Language Specification 4.12.4 :
La déclaration d'une variable finale peut servir de documentation utile que sa valeur ne changera pas et peut aider à éviter les erreurs de programmation.
Cependant, un modificateur final
sur un paramètre de méthode n'est pas mentionné dans les règles de correspondance des signatures des méthodes substituées, et il n'a aucun effet sur l'appelant, uniquement dans le corps d'une implémentation . De plus, comme l'a noté Robin dans un commentaire, le modificateur final
sur un paramètre de méthode n'a aucun effet sur le code d'octet généré. (Ce n'est pas vrai pour les autres utilisations de final
.)
Certains IDE copient la signature de la méthode abstraite/interface lors de l'insertion d'une méthode d'implémentation dans une sous-classe.
Je ne pense pas que cela fasse une différence pour le compilateur.
EDIT: Bien que je pense que cela était vrai dans le passé, je ne pense pas que les IDE actuels le font plus.
Les annotations finales des paramètres de méthode ne sont toujours pertinentes que pour l'implémentation de la méthode, jamais pour l'appelant. Par conséquent, il n'y a aucune raison réelle de les utiliser dans les signatures de méthode d'interface. À moins que vous ne vouliez suivre la même norme de codage cohérente, qui nécessite des paramètres de méthode finaux, dans toutes les signatures de méthode. Alors c'est bien de pouvoir le faire.
Mise à jour: La réponse originale ci-dessous a été écrite sans bien comprendre la question et ne répond donc pas directement à la question :)
Néanmoins, il doit être informatif pour ceux qui cherchent à comprendre l'utilisation générale du mot-clé final
.
Quant à la question, je voudrais citer mon propre commentaire d'en bas.
Je pense que vous n'êtes pas obligé d'implémenter la finalité d'un argument pour vous laisser libre de décider s'il doit être final ou non dans votre propre implémentation.
Mais oui, cela semble plutôt étrange que vous puissiez le déclarer
final
dans l'interface, mais l'avoir non final dans l'implémentation. Cela aurait été plus logique si:a.
final
le mot clé n'était pas autorisé pour les arguments de la méthode d'interface (abstraite) (mais vous pouvez l'utiliser dans l'implémentation), ou
b. déclarer un argument commefinal
dans l'interface le forcerait à être déclaréfinal
dans l'implémentation (mais pas forcé pour les non finales).
Je peux penser à deux raisons pour lesquelles une signature de méthode peut avoir des paramètres final
: Beans et Objects ( En fait, ils sont à la fois la même raison, mais des contextes légèrement différents. )
Objets:
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 ");
}
Le mot clé final
garantit que nous ne créerons pas accidentellement un nouveau pot de cuisson local en affichant une erreur de compilation lorsque nous avons tenté de le faire. Cela a garanti que le bouillon de poulet soit ajouté à notre marmite de cuisson d'origine obtenue par la méthode addChicken
. Comparez cela à addVegetables
où nous avons perdu le chou-fleur car il l'a ajouté à une nouvelle marmite locale au lieu de la marmite d'origine qu'il a obtenue.
Beans: C'est le même concept que les objets (comme illustré ci-dessus) . Les beans sont essentiellement Object
s en Java. Cependant, les beans (JavaBeans) sont utilisés dans diverses applications comme un moyen pratique de stocker et de transmettre une collection définie de données connexes. Tout comme le addVegetables
pourrait gâcher le processus de cuisson en créant un nouveau pot de cuisson StringBuilder
et en le jetant avec le chou-fleur, il pourrait également faire de même avec un pot de cuisson JavaBean .
Je pense que cela peut être un détail superflu, que ce soit final ou non est un détail de mise en œuvre.
(Un peu comme déclarer des méthodes/membres dans une interface comme publics.)