161 votes

mot-clé final dans les paramètres de la méthode

Je rencontre souvent des méthodes qui ressemblent à ce qui suit :

public void foo(final String a, final int[] b, final Object1 c){
}

Que se passe-t-il si cette méthode est appelée sans lui passer de paramètres finaux ? Par exemple, un objet 1 qui est modifié ultérieurement (et qui n'est donc pas déclaré comme final) peut être passé à cette méthode sans problème.

3 votes

@Joachim - en fait c'est la même chose que const en C ! La différence est qu'en Java, un "pointeur" vers un objet ne porte pas de nom particulier. * syntaxe. D'où la confusion ici. La variable est const/final, l'objet vers lequel elle pointe ne l'est pas.

0 votes

@Earwicker Je pense que je comprends votre point de vue, mais je pense que celui de Joachim est beaucoup plus précis en disant qu'un paramètre de méthode 'final' n'a aucune implication pour l'appelant, ce qui est vrai, mais pas vraiment ce que 'const' signifie en général.

0 votes

Par ailleurs, je pense que l'on voit souvent des méthodes déclarées de cette façon par des personnes qui pensent, à juste titre, qu'il est plus clair et moins sujet aux erreurs de ne pas traiter les paramètres des méthodes comme des variables locales qui peuvent changer. Le terme "final" ne fait qu'imposer cela.

211voto

Thirler Points 6222

Java fait toujours une copie des paramètres avant de les envoyer aux méthodes. Cela signifie que le caractère final ne fait aucune différence pour le code appelant. Cela signifie seulement qu'à l'intérieur de la méthode, les variables ne peuvent pas être réaffectées.

Notez que si vous avez un objet final, vous pouvez toujours modifier les attributs de l'objet. En effet, les objets en Java sont en réalité des pointeurs vers des objets. Et seul le pointeur est copié (et sera final dans votre méthode), pas l'objet réel.

73 votes

Il fait certainement une copie (il existe une optimisation où le compilateur ne fait pas de copie, alors qu'il n'y a aucune différence avec la copie). Cependant, vous devez garder à l'esprit que dans le cas d'un objet. L'objet n'est réellement qu'une référence à un objet. Dans ce cas, vous obtiendrez donc une copie de la référence.

0 votes

Si j'ai un int final et un thread dans ma méthode, puis-je encore changer la valeur de ce paramètre int depuis une autre méthode ?

22 votes

Il est vraiment indifférent que la valeur du paramètre soit une copie de la source de l'argument ou la même référence. Le fait est que toute variable n'est qu'une référence à l'objet réel en mémoire. Le fait de marquer un paramètre comme final interdit la réaffectation du paramètre dans le bloc de code de la fonction. Cependant, si le paramètre n'est pas final, bien que l'on puisse réaffecter le paramètre de l'argument passé à n'importe quoi d'autre, l'appelant de la fonction ne perd jamais sa référence et continue de pointer vers le même objet.

91voto

BalusC Points 498232

Il y a une circonstance où vous êtes requis de le déclarer final --sinon cela entraînera une erreur de compilation--, à savoir les faire passer dans des classes anonymes. Exemple de base :

public FileFilter createFileExtensionFilter(final String extension) {
    FileFilter fileFilter = new FileFilter() {
        public boolean accept(File pathname) {
            return pathname.getName().endsWith(extension);
        }
    };

    // What would happen when it's allowed to change extension here?
    // extension = "foo";

    return fileFilter;
}

Retirer le final entraînerait une erreur de compilation, car il n'est plus garanti que la valeur soit une constante d'exécution. La modification de la valeur depuis l'extérieur de la classe anonyme entraînerait notamment un comportement différent de l'instance de la classe anonyme après le moment de sa création.

1 votes

Quel serait l'effet du changement de la valeur de la variable (qui est déclarée comme finale) sur la classe interne ?

0 votes

Mais quand même, public boolean doesStringStartsWithZero(String str) throws Exception { boolean result = str.startsWith("0") ; str = "name" ; } Quelle est la différence entre l'exemple ci-dessus (avec la classe anonyme interne et cette méthode util) ?

61voto

Bozho Points 273663

Java n'est que pass-by-value. (ou mieux - pass-reference-by-value)

Donc l'argument passé et l'argument dans la méthode sont deux différents handlers pointant vers le même objet (valeur).

Par conséquent, si vous changez l'état de l'objet, elle est répercutée sur toutes les autres variables qui y font référence. Mais si vous réaffectez un nouvel objet (valeur) à l'argument, les autres variables qui pointent vers cet objet (valeur) ne sont pas réaffectées.

7 votes

Cette réponse n'aborde pas le sujet qui est "Le mot-clé final".

43voto

Erick G. Hagstrom Points 120

Le site final sur un paramètre de méthode ne signifie absolument rien pour l'appelant. Il ne signifie absolument rien non plus pour le programme en cours d'exécution, puisque sa présence ou son absence ne modifie pas le bytecode. Il garantit seulement que le compilateur se plaindra si la variable du paramètre est réaffectée au sein de la méthode. C'est tout. Mais c'est suffisant.

Certains programmateurs (comme moi) pensent que c'est une très bonne chose et utilisent final sur presque tous les paramètres. Cela facilite la compréhension d'une méthode longue ou complexe (bien que l'on puisse dire que les méthodes longues et complexes devraient être remaniées). ne sont pas marqué avec final .

1 votes

Je trouve que cela ressemble plus à une convention dans les équipes. Il n'y a pas vraiment de bonne ou de mauvaise réponse. Cependant, je suis plutôt d'accord avec @Erick G. HagstromErick. Avoir final sur les paramètres des méthodes vous aide à comprendre les sorties de la méthode au premier coup d'œil, et attire l'attention sur les paramètres non finaux.

22voto

netzwerg Points 1635

Considérez cette implémentation de foo() :

public void foo(final String a) {
    SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            System.out.print(a);
        }
    }); 
}

Parce que le Runnable survivrait à la méthode, cela ne pourrait pas être compilé sans l'attribut final mot-clé -- final indique au compilateur qu'il est possible de prendre une copie de la référence (pour s'y référer plus tard). Ainsi, c'est le référence qui est considéré comme définitif, et non pas le valeur . En d'autres termes : En tant qu'appelant, vous ne pouvez rien gâcher...

0 votes

C'est un très bon point. Il s'agit d'un cas particulier de l'exigence selon laquelle les variables d'une portée englobante qui sont référencées dans une classe interne anonyme doivent être finales, mais il offre néanmoins une bonne raison pour qu'au moins certains paramètres de méthode soient finaux.

1 votes

Ce n'est pas "Parce que l'instance Runnable survivrait à la méthode", cependant. C'est vrai pour toute classe interne anonyme.

2 votes

Oh, et maintenant dans Java 8 nous avons le concept effectivement final.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X