Pourquoi devrais-je utiliser le mot-clé «final» sur un paramètre de méthode en Java?

381

Je ne peux pas comprendre où le finalmot-clé est vraiment pratique lorsqu'il est utilisé sur des paramètres de méthode.

Si nous excluons l'utilisation de classes anonymes, la lisibilité et la déclaration d'intention, cela me semble presque sans valeur.

Faire en sorte que certaines données restent constantes n'est pas aussi solide qu'il y paraît.

  • Si le paramètre est une primitive, il n'aura aucun effet puisque le paramètre est transmis à la méthode en tant que valeur et sa modification n'aura aucun effet en dehors de la portée.

  • Si nous transmettons un paramètre par référence, alors la référence elle-même est une variable locale et si la référence est modifiée de l'intérieur de la méthode, cela n'aurait aucun effet de l'extérieur de la portée de la méthode.

Considérez l'exemple de test simple ci-dessous. Ce test réussit bien que la méthode ait changé la valeur de la référence qui lui a été donnée, il n'a aucun effet.

public void testNullify() {
    Collection<Integer> c  = new ArrayList<Integer>();      
    nullify(c);
    assertNotNull(c);       
    final Collection<Integer> c1 = c;
    assertTrue(c1.equals(c));
    change(c);
    assertTrue(c1.equals(c));
}

private void change(Collection<Integer> c) {
    c = new ArrayList<Integer>();
}

public void nullify(Collection<?> t) {
    t = null;
}
Basil Bourque
la source
101
Un point rapide sur la terminologie - Java n'a pas du tout de référence. Il a une référence de passage par valeur qui n'est pas la même chose. Avec une vraie sémantique de passage par référence, les résultats de votre code seraient différents.
Jon Skeet
6
Quelle est la différence entre passer par référence et passer référence par valeur?
NobleUplift
Il est plus facile de décrire cette différence dans un contexte C (du moins pour moi). Si je passe un pointeur vers une méthode comme: <code> int foo (int bar) </code>, alors ce pointeur est passé par valeur. Cela signifie qu'il est copié, donc si je fais quelque chose à l'intérieur de cette méthode comme <code> free (bar); bar = malloc (...); </code> alors je viens de faire une très mauvaise chose. L'appel gratuit libérera en fait le morceau de mémoire pointé (donc le pointeur que je suis passé est maintenant suspendu). Cependant, <code> int foo (int & bar) </bar> signifie que le code est valide et que la valeur du pointeur transmis sera modifiée.
jerslan
1
Le premier est censé être int foo(int* bar)et le dernier int foo(int* &bar). Ce dernier passe un pointeur par référence, le premier passe une référence par valeur.
jerslan
2
@Martin, à mon avis, c'est une bonne question ; voir le titre de la question et le contenu du message pour expliquer pourquoi la question est posée. Peut-être que je me méprends sur les règles ici, mais c'est exactement la question que je voulais en recherchant "les utilisations des paramètres finaux dans les méthodes" .
Victor Zamanian

Réponses:

239

Arrêter la réaffectation d'une variable

Bien que ces réponses soient intellectuellement intéressantes, je n'ai pas lu la réponse simple et courte:

Utilisez le mot-clé final lorsque vous souhaitez que le compilateur empêche qu'une variable soit réaffectée à un autre objet.

Que la variable soit une variable statique, une variable membre, une variable locale ou une variable argument / paramètre, l'effet est entièrement le même.

Exemple

Voyons l'effet en action.

Considérez cette méthode simple, où les deux variables ( arg et x ) peuvent toutes deux être réaffectées à des objets différents.

// Example use of this method: 
//   this.doSomething( "tiger" );
void doSomething( String arg ) {
  String x = arg;   // Both variables now point to the same String object.
  x = "elephant";   // This variable now points to a different String object.
  arg = "giraffe";  // Ditto. Now neither variable points to the original passed String.
}

Marquez la variable locale comme finale . Il en résulte une erreur de compilation.

void doSomething( String arg ) {
  final String x = arg;  // Mark variable as 'final'.
  x = "elephant";  // Compiler error: The final local variable x cannot be assigned. 
  arg = "giraffe";  
}

Au lieu de cela, marquons la variable de paramètre comme finale . Cela entraîne également une erreur de compilation.

void doSomething( final String arg ) {  // Mark argument as 'final'.
  String x = arg;   
  x = "elephant"; 
  arg = "giraffe";  // Compiler error: The passed argument variable arg cannot be re-assigned to another object.
}

Morale de l'histoire:

Si vous voulez vous assurer qu'une variable pointe toujours vers le même objet, marquez la variable finale .

Ne jamais réaffecter d'arguments

Comme bonne pratique de programmation (dans n'importe quel langage), vous ne devez jamais réaffecter une variable de paramètre / argument à un objet autre que l'objet passé par la méthode appelante. Dans les exemples ci-dessus, il ne faut jamais écrire la ligne arg =. Puisque les humains font des erreurs et que les programmeurs sont humains, demandons au compilateur de nous aider. Marquez chaque variable de paramètre / argument comme «finale» afin que le compilateur puisse trouver et marquer de telles réaffectations.

En rétrospective

Comme indiqué dans d'autres réponses… Étant donné l'objectif de conception original de Java d'aider les programmeurs à éviter les erreurs stupides telles que la lecture après la fin d'un tableau, Java aurait dû être conçu pour appliquer automatiquement toutes les variables de paramètre / argument comme «finales». En d'autres termes, les arguments ne doivent pas être des variables . Mais le recul est une vision de 20/20, et les concepteurs Java avaient les mains pleines à l'époque.

Alors, toujours ajouter finalà tous les arguments?

Devrions-nous ajouter finalà chaque paramètre de méthode déclaré?

  • En théorie, oui.
  • En pratique, non.
    ➥ Ajouter finaluniquement lorsque le code de la méthode est long ou compliqué, où l'argument peut être confondu avec une variable locale ou membre et éventuellement réaffecté.

Si vous achetez dans la pratique de ne jamais réattribuer un argument, vous serez enclin à ajouter un finalà chacun. Mais cela est fastidieux et rend la déclaration un peu plus difficile à lire.

Pour un code simple court où l'argument est évidemment un argument, et non une variable locale ni une variable membre, je ne me donne pas la peine d'ajouter le final. Si le code est assez évident, sans aucune chance pour moi ni pour aucun autre programmeur de faire de la maintenance ou de refactoriser par erreur la variable argument comme autre chose qu'un argument, alors ne vous embêtez pas. Dans mon propre travail, j'ajoute finaluniquement du code plus long ou plus impliqué où un argument peut être confondu avec une variable locale ou membre.

Un autre cas ajouté pour l'exhaustivité

public class MyClass {
    private int x;
    //getters and setters
}

void doSomething( final MyClass arg ) {  // Mark argument as 'final'.

   arg =  new MyClass();  // Compiler error: The passed argument variable arg  cannot be re-assigned to another object.

   arg.setX(20); // allowed
  // We can re-assign properties of argument which is marked as final
 }
Basil Bourque
la source
23
"En tant que bonne pratique de programmation (dans n'importe quel langage), vous ne devez jamais réaffecter une variable de paramètre / argument [..]" Désolé, je dois vraiment vous appeler à ce sujet. Réaffecter des arguments est une pratique standard dans des langages comme Javascript, où la quantité d'arguments passés (ou même s'il y en a) n'est pas dictée par la signature de la méthode. Par exemple, étant donné une signature comme: "function say (msg)", les gens s'assureront que l'argument 'msg' est assigné, comme ceci: "msg = msg || 'Hello World!';". Les meilleurs programmeurs Javascript du monde enfreignent vos bonnes pratiques. Lisez simplement la source jQuery.
Stijn de Witt
37
@StijndeWitt Votre exemple montre le problème même de la réaffectation de la variable d'argument. Vous perdez des informations sans rien en retour: (a) Vous avez perdu la valeur d'origine transmise, (b) Vous avez perdu l'intention de la méthode d'appel (l'appelant a-t-il passé «Hello World!» Ou avons-nous par défaut). Les deux a & b sont utiles pour les tests, le code long et lorsque la valeur est modifiée ultérieurement. Je maintiens ma déclaration: arg vars ne doit jamais être réaffecté. Votre code doit être: message = ( msg || 'Hello World"' ). Il n'y a tout simplement aucune raison de ne pas utiliser une var distincte. Le seul coût est de quelques octets de mémoire.
Basil Bourque
9
@Basil: C'est plus de code (en octets) et en Javascript qui compte. Fortement. Comme pour beaucoup de choses, c'est basé sur l'opinion. Il est tout à fait possible d'ignorer complètement cette pratique de programmation et d'écrire toujours un excellent code. La pratique de programmation d'une seule personne ne fait pas de la pratique de tout le monde. Tenez-vous-en à tout ce que vous voudrez, je choisis de l'écrire différemment de toute façon. Cela fait-il de moi un mauvais programmeur ou mon code est-il un mauvais code?
Stijn de Witt
14
L'usage message = ( msg || 'Hello World"' )me risque plus tard d'utiliser accidentellement msg. Lorsque le contrat que j'entends est «un comportement sans arg / nul / non défini ne peut être ignoré "Hello World"», c'est une bonne pratique de programmation de s'y engager tôt dans la fonction. [Cela peut être réalisé sans réaffectation en commençant par if (!msg) return myfunc("Hello World");mais cela devient difficile à utiliser avec plusieurs arguments.] Dans les rares cas où la logique de la fonction devrait se soucier de savoir si la valeur par défaut a été utilisée, je préfère désigner une valeur sentinelle spéciale (de préférence publique) .
Beni Cherniavsky-Paskin
6
@ BeniCherniavsky-Paskin le risque que vous décrivez n'est dû qu'à la similitude entre messageet msg. Mais s'il l'appelle quelque chose comme processedMsgou quelque chose d'autre qui fournit un contexte supplémentaire - le risque d'erreur est beaucoup plus faible. Concentrez-vous sur ce qu'il dit et non sur «comment» il le dit. ;)
alfasin
230

Parfois, il est agréable d'être explicite (pour plus de lisibilité) que la variable ne change pas. Voici un exemple simple où l'utilisation finalpeut sauver certains maux de tête possibles:

public void setTest(String test) {
    test = test;
}

Si vous oubliez le mot-clé «this» sur un setter, la variable que vous souhaitez définir ne sera pas définie. Cependant, si vous avez utilisé le finalmot clé sur le paramètre, le bogue serait détecté au moment de la compilation.

Jerry Sha
la source
65
btw vous verrez l'avertissement "L'affectation au test de variable n'a aucun effet" de toute façon
AvrDragon
12
@AvrDragon Mais, nous pourrions également ignorer l'avertissement. Il est donc toujours préférable d'avoir quelque chose qui nous empêchera d'aller plus loin, comme une erreur de compilation, que nous obtiendrons en utilisant le mot-clé final.
Sumit Desai
10
@AvrDragon Cela dépend de l'environnement de développement. Vous ne devriez pas compter sur l'IDE pour attraper des trucs comme ça de toute façon, sauf si vous voulez développer de mauvaises habitudes.
b1nary.atr0phy
25
@ b1naryatr0phy en fait c'est un avertissement du compilateur, pas seulement IDE-tip
AvrDragon
8
@SumitDesai "Mais, nous pourrions également ignorer l'avertissement. Donc, il est toujours préférable d'avoir quelque chose qui nous empêchera d'aller plus loin, comme une erreur de compilation, que nous obtiendrons en utilisant le mot-clé final." Je prends votre point de vue, mais c'est une déclaration très forte avec laquelle je pense que de nombreux développeurs Java ne seraient pas d'accord. Les avertissements du compilateur sont là pour une raison et un développeur compétent ne devrait pas avoir besoin d'une erreur pour les «forcer» à considérer ses implications.
Stuart Rossiter
127

Oui, à l'exception des classes anonymes, de la lisibilité et de la déclaration d'intention, c'est presque sans valeur. Ces trois choses sont-elles cependant sans valeur?

Personnellement, j'ai tendance à ne pas utiliser finalde variables et de paramètres locaux, sauf si j'utilise la variable dans une classe interne anonyme, mais je peux certainement voir l'intérêt de ceux qui veulent préciser que la valeur du paramètre ne changera pas (même si l'objet auquel il se réfère change de contenu). Pour ceux qui trouvent que cela ajoute à la lisibilité, je pense que c'est une chose tout à fait raisonnable à faire.

Votre point serait plus important si quelqu'un prétend en fait que ce ne garder constant de données d'une manière qu'il ne fonctionne pas - mais je ne me souviens pas avoir vu de telles réclamations. Suggérez-vous qu'il existe un nombre important de développeurs suggérant que cela finala plus d'effet qu'il ne le fait vraiment?

EDIT: J'aurais vraiment dû résumer tout cela avec une référence Monty Python; la question semble quelque peu similaire à demander "Qu'est-ce que les Romains ont fait pour nous?"

Jon Skeet
la source
17
Mais pour paraphraser Krusty avec son danois, qu'ont- ils fait pour nous TOTALEMENT ? =)
James Schek
Yuval. Ca c'est drôle! Je suppose que la paix peut arriver même si elle est imposée par une lame d'épée!
gonzobrains
1
La question semble plus similaire à la question: "Qu'est - ce que les Romains n'ont pas fait pour nous?", Car il s'agit davantage d'une critique de ce que le mot clé final ne fait pas .
NobleUplift
"Suggérez-vous qu'il existe un nombre important de développeurs suggérant que la version finale a plus d'effet qu'elle ne le fait vraiment?" Pour moi , c'est le principal problème: je soupçonne fortement une part importante de développeurs utilisant pense qu'il applique immuabilité du de l' appelant des éléments transmis quand il ne fonctionne pas. Bien sûr, on se retrouve alors entraîné dans le débat sur la question de savoir si les normes de codage devraient «protéger contre» les malentendus conceptuels (dont un développeur «compétent» devrait être conscient) ou non (et cela se dirige ensuite vers des avis hors de la portée des SO -type question)!
Stuart Rossiter
1
@SarthakMittal: La valeur ne sera copiée que si vous l'utilisez réellement, si c'est ce que vous vous demandez.
Jon Skeet
76

Permettez-moi d'expliquer un peu le cas où vous devez utiliser final, que Jon a déjà mentionné:

Si vous créez une classe interne anonyme dans votre méthode et utilisez une variable locale (comme un paramètre de méthode) à l'intérieur de cette classe, le compilateur vous oblige à rendre le paramètre final:

public Iterator<Integer> createIntegerIterator(final int from, final int to)
{
    return new Iterator<Integer>(){
        int index = from;
        public Integer next()
        {
            return index++;
        }
        public boolean hasNext()
        {
            return index <= to;
        }
        // remove method omitted
    };
}

Ici, les paramètres fromet todoivent être définitifs pour pouvoir être utilisés dans la classe anonyme.

La raison de cette exigence est la suivante: les variables locales vivent sur la pile, elles n'existent donc que pendant l'exécution de la méthode. Cependant, l'instance de classe anonyme est renvoyée par la méthode, elle peut donc vivre beaucoup plus longtemps. Vous ne pouvez pas conserver la pile, car elle est nécessaire pour les appels de méthode suivants.

Donc, ce que Java fait à la place, c'est de mettre des copies de ces variables locales en tant que variables d'instance cachées dans la classe anonyme (vous pouvez les voir si vous examinez le code d'octet). Mais s'ils n'étaient pas définitifs, on pourrait s'attendre à ce que la classe anonyme et la méthode voient les changements que l'autre apporte à la variable. Afin de maintenir l'illusion qu'il n'y a qu'une seule variable plutôt que deux copies, elle doit être définitive.

Michael Borgwardt
la source
1
Vous m'avez perdu de "Mais s'ils ne sont pas définitifs ..." Pouvez-vous mettre essayer de reformuler, Peut-être que je n'ai pas eu assez de café.
hhafez
1
Vous avez une variable locale de - la question est de savoir ce qui se passe si vous utilisez l'instance de classe anon à l'intérieur de la méthode et qu'elle modifie les valeurs de - les gens s'attendent à ce que le changement soit visible dans la méthode, car ils ne voient qu'une seule variable. Afin d'éviter cette confusion, elle doit être définitive.
Michael Borgwardt
Il ne fait pas de copie, c'est simplement une référence à n'importe quel objet référencé.
vickirk
1
@vickirk: bien sûr, il fait une copie - de la référence, en cas de types de référence.
Michael Borgwardt
En supposant que nous n'avons pas de classes anonymes référençant ces variables, savez-vous s'il existe une différence entre un finalparamètre de fonction et un paramètre de fonction non final aux yeux de HotSpot?
Pacerier
25

J'utilise la finale tout le temps sur les paramètres.

Cela ajoute-t-il autant? Pas vraiment.

Vais-je l'éteindre? Non.

La raison: j'ai trouvé 3 bugs où les gens avaient écrit du code bâclé et n'ont pas réussi à définir une variable membre dans les accesseurs. Tous les bogues se sont révélés difficiles à trouver.

J'aimerais voir cela devenir le défaut dans une future version de Java. Le passage par valeur / référence fait monter énormément de programmeurs juniors.

Une dernière chose .. mes méthodes ont tendance à avoir un petit nombre de paramètres, donc le texte supplémentaire sur une déclaration de méthode n'est pas un problème.

Fortyrunner
la source
4
J'étais sur le point de suggérer cela également, que final soit la valeur par défaut dans les futures versions et que vous devez spécifier un mot clé "mutable" ou meilleur qui est conçu. Voici un bel article à ce sujet: lpar.ath0.com/2008/08/26/java-annoyance-final-parameters
Jeff Axelrod
Cela fait longtemps, mais pourriez-vous fournir un exemple du bug que vous avez détecté?
user949300
Voir la réponse la plus votée. Cela a un très bon exemple où la variable membre n'est pas définie et à la place le paramètre est muté.
Fortyrunner
18

L'utilisation de final dans un paramètre de méthode n'a rien à voir avec ce qui arrive à l'argument du côté de l'appelant. Il est uniquement destiné à le marquer comme ne changeant pas à l'intérieur de cette méthode. Alors que j'essaie d'adopter un style de programmation plus fonctionnel, j'en vois la valeur.

Allemand
la source
2
Exactement, cela ne fait pas partie de l'interface de fonction, seulement de l'implémentation. Il est déroutant que java autorise (mais dirsregards) final les paramètres dans les déclarations d'interfaces / méthodes abstraites.
Beni Cherniavsky-Paskin
8

Personnellement, je n'utilise pas final sur les paramètres de méthode, car cela ajoute trop d'encombrement aux listes de paramètres. Je préfère imposer que les paramètres de méthode ne soient pas modifiés par quelque chose comme Checkstyle.

Pour les variables locales que j'utilise final dans la mesure du possible, je laisse même Eclipse le faire automatiquement dans ma configuration pour des projets personnels.

Je voudrais certainement quelque chose de plus fort comme C / C ++ const.

starblue
la source
Je ne suis pas sûr que les références d'IDE et d'outils soient applicables à la publication OP ou au sujet. A savoir "final" est une vérification au moment de la compilation que la référence n'est pas modifiée / agressée. De plus, pour vraiment appliquer de telles choses, voir la réponse concernant l'absence de protection des enfants membres des références finales. Lors de la construction d'une API par exemple, l'utilisation d'un IDE ou d'un outil ne va pas aider les parties externes à utiliser / étendre ce code.
Darrell Teague
4

Étant donné que Java transmet des copies d'arguments, je pense que la pertinence de finalest plutôt limitée. Je suppose que l'habitude vient de l'ère C ++ où vous pouviez interdire la modification du contenu de référence en faisant a const char const *. Je pense que ce genre de choses vous fait croire que le développeur est intrinsèquement stupide comme f *** et doit être protégé contre vraiment tous les personnages qu'il tape. En toute humilité, je peux dire que j'écris très peu de bogues même si j'en omet final(sauf si je ne veux pas que quelqu'un écrase mes méthodes et mes classes). Peut-être que je suis juste un développeur de la vieille école.

Lawrence
la source
1

Je n'utilise jamais final dans une liste de paramètres, cela ajoute simplement de l'encombrement comme l'ont dit les répondants précédents. Dans Eclipse, vous pouvez également définir l'attribution des paramètres pour générer une erreur, donc l'utilisation de final dans une liste de paramètres me semble assez redondante. Fait intéressant, lorsque j'ai activé le réglage Eclipse pour l'attribution des paramètres, générant une erreur, il a détecté ce code (c'est juste ainsi que je me souviens du flux, pas du code réel.): -

private String getString(String A, int i, String B, String C)
{
    if (i > 0)
        A += B;

    if (i > 100)
        A += C;

    return A;
}

En jouant l'avocat du diable, qu'est-ce qui ne va pas exactement avec ça?

Chris Milburn
la source
Soyez attentif à différencier un IDE d'une JVM d'exécution. Quoi que fasse un IDE, cela n'a aucune importance lorsque le code d'octets compilé s'exécute sur le serveur, à moins que l'IDE n'ait ajouté du code pour se protéger contre le mugging des variables membres, comme une faille dans le code alors qu'il était prévu qu'une variable ne soit pas réaffectée mais qu'elle l'était par erreur - d'où le but de mot-clé final.
Darrell Teague
1

Réponse courte: finalaide un tout petit peu mais ... utilisez plutôt une programmation défensive côté client.

En effet, le problème finalest qu'il n'impose que la référence est inchangée, permettant joyeusement aux membres de l'objet référencé d'être mutés, à l'insu de l'appelant. Par conséquent, la meilleure pratique à cet égard est la programmation défensive du côté de l'appelant, créant des instances profondément immuables ou des copies profondes d'objets qui risquent d'être agressés par des API sans scrupules.

Darrell Teague
la source
2
"le problème avec final est qu'il ne fait qu'appliquer la référence inchangée" - Faux, Java lui-même empêche cela. Une variable passée dans une méthode ne peut pas avoir sa référence modifiée par cette méthode.
Madbreaks
Veuillez rechercher avant de publier ... stackoverflow.com/questions/40480/…
Darrell Teague
Autrement dit, s'il était vrai que les références aux références ne peuvent pas être modifiées, il n'y aurait pas de discussion sur la copie défensive, l'immuabilité, pas besoin de mot-clé final, etc.
Darrell Teague
Soit vous me comprenez mal, soit vous vous trompez. Si je passe une référence d'objet à une méthode et que cette méthode la réaffecte, la référence d'origine reste intacte pour (moi) l'appelant lorsque la méthode termine son exécution. Java est strictement pass-by-value. Et vous êtes effrontément présomptueux d'affirmer que je n'ai fait aucune recherche.
Madbreaks
Downvoting parce qu'op a demandé pourquoi utiliser final, et vous avez donné une seule raison incorrecte.
Madbreaks
0

Une raison supplémentaire d'ajouter des déclarations finales aux paramètres est qu'elle permet d'identifier les variables qui doivent être renommées dans le cadre d'une refactorisation de la "méthode d'extraction". J'ai constaté que l'ajout de final à chaque paramètre avant de démarrer une refactorisation de grande méthode me dit rapidement s'il y a des problèmes que je dois résoudre avant de continuer.

Cependant, je les supprime généralement comme superflus à la fin du refactoring.

Michael Rutherfurd
la source
-1

Suivi de ce post de Michel. J'ai moi-même fait un autre exemple pour l'expliquer. J'espère que ça pourrait aider.

public static void main(String[] args){
    MyParam myParam = thisIsWhy(new MyObj());
    myParam.setArgNewName();

    System.out.println(myParam.showObjName());
}

public static MyParam thisIsWhy(final MyObj obj){
    MyParam myParam = new MyParam() {
        @Override
        public void setArgNewName() {
            obj.name = "afterSet";
        }

        @Override
        public String showObjName(){
            return obj.name;
        }
    };

    return myParam;
}

public static class MyObj{
    String name = "beforeSet";
    public MyObj() {
    }
}

public abstract static class MyParam{
    public abstract void setArgNewName();
    public abstract String showObjName();
}

À partir du code ci - dessus, dans la méthode thisIsWhy () , nous avons en fait ne pas assignons le [ l' argument MyObj obj] à une véritable référence en MyParam. À la place, nous utilisons simplement [l'argument MyObj obj] dans la méthode à l'intérieur de MyParam.

Mais après avoir terminé la méthode thisIsWhy () , l'argument (objet) MyObj devrait-il toujours exister?

Il semble que ce soit le cas, parce que nous pouvons voir que nous appelons toujours la méthode showObjName () et qu'elle doit atteindre obj . MyParam utilisera / atteint toujours l'argument de la méthode même si la méthode était déjà de retour!

Comment Java y parvient vraiment est de générer une copie est également une référence cachée de l' argument MyObj obj à l'intérieur de l'objet MyParam (mais ce n'est pas un champ formel dans MyParam afin que nous ne puissions pas le voir)

Comme nous appelons "showObjName", il utilisera cette référence pour obtenir la valeur correspondante.

Mais si nous n'avons pas mis l'argument final, ce qui conduit à une situation, nous pouvons réaffecter une nouvelle mémoire (objet) à l' argument MyObj obj .

Techniquement, il n'y a pas de conflit du tout! Si nous sommes autorisés à le faire, voici la situation:

  1. Nous avons maintenant un point [MyObj obj] caché vers un [Mémoire A en tas] vivant maintenant dans l'objet MyParam.
  2. Nous avons également un autre [MyObj obj] qui est l'argument pointant vers un [Memory B in heap] vivant maintenant dans la méthode thisIsWhy.

Pas d'affrontement, mais "CONFUSANT !!" Parce qu'ils utilisent tous le même "nom de référence" qui est "obj" .

Pour éviter cela, définissez-le comme "final" pour éviter que le programmeur ne fasse le code "sujet aux erreurs".

KunYu Tsai
la source