368 votes

Pourquoi "final" n'est pas autorisé dans les méthodes d'interface Java 8?

L'une des caractéristiques les plus utiles de Java 8 sont les nouveaux default méthodes sur les interfaces. Il y a essentiellement deux raisons (il peut y en avoir d'autres) pourquoi ils ont été introduits:

À partir d'une API designer point de vue, j'aurais aimé être capable d'utiliser d'autres modificateurs sur les méthodes d'interface, par exemple, final. Cela peut être utile lors de l'ajout de méthodes pratiques, la prévention "accidentelle" remplace dans la mise en œuvre des classes:

interface Sender {

    // Convenience method to send an empty message
    default final void send() {
        send(null);
    }

    // Implementations should only implement this method
    void send(String message);
}

Le ci-dessus est déjà pratique courante si Sender ont une classe:

abstract class Sender {

    // Convenience method to send an empty message
    final void send() {
        send(null);
    }

    // Implementations should only implement this method
    abstract void send(String message);
}

Maintenant, default et final sont évidemment contradictoires mots-clés, mais le mot clé default lui-même n'aurait pas été strictement nécessaire, donc je suis en supposant que cette contradiction est délibérée, afin de refléter les différences subtiles entre les "méthodes de la classe avec le corps" (juste des méthodes) et "les méthodes d'interface avec le corps" (méthodes par défaut), c'est à dire les différences qui je n'ai pas encore compris.

À un certain moment, le soutien pour les modificateurs comme static et final sur les méthodes d'interface n'est pas encore totalement exploré, citant Brian Goetz:

L'autre partie c'est la façon dont nous allons aller à la classe de soutien-bâtiment outils d'interfaces, telles que la finale de méthodes, les méthodes privées, protégées des méthodes, des méthodes statiques, etc. La réponse est: nous ne savons pas encore

Depuis ce temps, à la fin de 2011, à l'évidence, le soutien pour l' static méthodes des interfaces a été ajouté. Clairement, cela ajoute beaucoup de valeur à la JDK les bibliothèques elles-mêmes, comme avec Comparator.comparing().

Question:

Quelle est la raison final (et aussi static final) n'a jamais fait de Java 8 interfaces?


Note, avant que cette question est très fermé: Pour ajustement de Débordement de Pile Q&r format: je suis à la recherche d'autorité citations seulement, pas de la spéculation. Une réponse ferme à cette question sera probablement aider beaucoup de futurs visiteurs de cette question, donc merci de ne pas le fermer avec impatience.

468voto

Brian Goetz Points 6062

Cette question est, dans une certaine mesure, liée à Ce qui est la raison pour laquelle "synchronisé" n'est pas autorisé dans Java 8 méthodes d'interface?

La chose à comprendre au sujet des méthodes par défaut, c'est que le but premier de la conception est l' évolution de l'interface, à ne pas "tourner interfaces (médiocre) des traits". Bien qu'il y ait un certain chevauchement entre les deux, et nous avons essayé d'être accommodant à la dernière où il n'a pas obtenir de la manière de l'ancien, ces questions sont mieux compris lorsqu'ils sont affichés dans cette lumière. (Remarque aussi que les méthodes de la classe sont va être différent de méthodes d'interface, quelle que soit l'intention, en vertu du fait que les méthodes d'interface peut être multiplier hérité.)

L'idée de base d'une méthode par défaut est: c'est une méthode d'interface avec un défaut de mise en œuvre, et une classe dérivée peut fournir plus spécifiques de mise en œuvre. Et parce que le centre de design a évolution de l'interface, il était un critique objectif de la conception que les méthodes par défaut pourra être ajouté à des interfaces après le fait dans une source compatible et compatible au niveau binaire.

Le trop-simple réponse à "pourquoi ne pas finale méthodes par défaut" c'est qu'alors le corps serait alors de ne pas être tout simplement le défaut de mise en œuvre, il serait le seul de la mise en œuvre. Alors que c'est un peu trop simple d'y répondre, il nous donne un indice que la question est déjà en route dans une douteuse direction.

Une autre raison pourquoi interface finale méthodes sont discutables, c'est qu'ils impossible de créer des problèmes pour les développeurs. Par exemple, supposons que vous avez:

interface A { 
    default void foo() { ... }
}

interface B { 
}

class C implements A, B { 
}

Ici, tout est bon; C hérite de foo() de A. Maintenant, en supposant que B est modifié pour avoir une méthode foo, avec une valeur par défaut:

interface B { 
    default void foo() { ... }
}

Maintenant, quand nous allons à recompiler C, le compilateur va nous dire qu'il ne sait pas ce comportement d'hériter pour foo(), de sorte que C est pour le remplacer (et peut choisir de déléguer à l' A.super.foo() si elle voulait conserver le même comportement.) Mais que faire si B avait fait de son défaut final, et n'est pas sous le contrôle de l'auteur de C? Maintenant C est irrémédiablement cassé; il ne peut pas compiler sans écraser foo(), mais il ne peut pas remplacer foo() si elle était définitive en B.

C'est juste un exemple, mais le point est que le résultat final méthodes sont vraiment un outil qui fait plus de sens dans le monde de l'unique héritage de classes (généralement en couple état pour le comportement), que pour les interfaces qui contribuent simplement le comportement et peut être multiplier hérité. C'est trop dur à raison à propos de "ce que les autres interfaces peut être mélangé dans l'éventuelle réalisateur", et en permettant à une méthode d'interface final serait probablement la cause de ces problèmes (et ils le feraient sauter pas sur la personne qui a écrit l'interface, mais sur les pauvres de l'utilisateur qui tente de la mettre en œuvre.)

Une autre raison pour les interdire, c'est qu'ils ne serait pas dire ce que vous pensez qu'ils veulent dire. Un défaut de mise en œuvre est prise en compte uniquement si la classe (ou de ses super-classes) ne pas fournir une déclaration (concrète ou abstraite) de la méthode. Si une méthode par défaut ont été finale, mais une super-classe déjà mis en œuvre la méthode, la valeur par défaut sera ignoré, ce qui n'est probablement pas ce que la valeur par défaut de l'auteur m'attendais lors de la déclaration définitive. (Ce comportement de l'héritage est un reflet de la conception du centre des méthodes par défaut -- évolution de l'interface. Il devrait être possible d'ajouter une valeur par défaut de la méthode (ou un défaut de mise en œuvre à une méthode d'interface) pour les interfaces existantes qui ont déjà mises en œuvre, sans changer le comportement de l'existant des classes qui implémentent l'interface, afin de garantir que les classes qui ont déjà travaillé avant le défaut méthodes ont été ajoutées fonctionnera de la même manière en présence de méthodes par défaut.)

45voto

Edwin Dalorzo Points 19899

Dans le lambda liste de diffusion il y a beaucoup de discussions à ce sujet. L'un de ceux qui semble contenir beaucoup de discussions à propos de tout ça est la suivante: On a Varié la méthode de l'interface de la visibilité (a Final défenseurs).

Dans cette discussion, Talden, l'auteur de la question initiale demande quelque chose de très similaire à votre question:

La décision de faire de tous les membres d'interface public était en effet un décision regrettable. Que toute utilisation de l'interface de conception interne expose la mise en œuvre d'informations privées est un grand.

C'est une question difficile à résoudre sans l'ajout de certains obscur ou de compatibilité casser les nuances de la langue. Une rupture de compatibilité de l'ampleur et le potentiel de subtilité aurait vu inique donc un la solution doit exister qui ne se casse pas le code existant.

Pourrait réintroduire le "package" clé d'accès-spécificateur être viable. C'est l'absence d'un spécificateur dans une interface impliquerait d'accès public et l'absence d'un spécificateur de classe implique package d'accès. Qui spécificateurs de sens que dans une interface n'est pas claire - surtout si, pour minimiser la connaissance fardeau sur les développeurs, nous devons nous assurer que l'accès spécificateurs de dire la même chose dans les deux classe et d'interface si ils sont présents.

En l'absence de méthodes par défaut j'aurais supposé que l' spécificateur d'un membre dans une interface doit être au moins aussi visible que les l'interface elle-même (si l'interface peut être effectivement mise en place tous les contextes) - avec des méthodes par défaut qui n'est pas si certain.

Il y a eu toute une communication claire quant à savoir si c'est encore un possible de la portée de la discussion? Si non, doit-il être occupé ailleurs.

Finalement, Brian Goetz réponse a été:

Oui, c'est déjà explorées.

Toutefois, permettez-moi de définir certaines des attentes réalistes -- language / VM les caractéristiques ont un long délai, même triviale-semblant comme cela. Le temps pour proposer de nouvelles fonctionnalité du langage idées pour Java SE 8 a assez bien passé.

Donc, très probablement, il n'a jamais été mis en œuvre parce qu'il n'a jamais fait partie de la portée. Il n'a jamais été proposé dans les délais prévus.

Dans une autre discussion à propos de final défenseur des méthodes sur le sujet, Brian a dit encore:

Et vous avez obtenu exactement ce que vous avez souhaité. C'est exactement ce que cette fonctionnalité ajoute -- l'héritage multiple de comportement. Bien sûr, nous comprendre que les gens vont les utiliser comme des traits. Et nous avons travaillé dur pour s'assurer que le modèle de l'héritage qu'ils offrent est simple et assez propre que les gens peuvent obtenir de bons résultats dans un large variété de situations. Nous avons, dans le même temps, choisi de ne pas pousser au-delà de la limite de ce qui fonctionne simplement et proprement, et que "oh, vous n'allez pas assez loin" réactions dans certains cas. Mais vraiment, la plupart de ce fil semble être plaignent que le verre est simplement 98%. Je vais prendre que 98% et de s'en sortir!

Donc, cela renforce ma théorie qu'il n'était tout simplement pas partie de la portée ou de la partie de leur conception. Ce qu'ils ont fait était de fournir suffisamment de fonctionnalités pour traiter les problèmes de l'API de l'évolution.

18voto

Marco13 Points 14743

Il sera difficile de trouver et d'identifier des "LA" réponse, pour les resons mentionné dans les commentaires de @EJP : Il y a environ 2 (+/- 2) personnes dans le monde qui peut donner la réponse définitive à tous. Et dans le doute, la réponse est peut-être juste quelque chose comme "le Soutien de finale par défaut méthodes ne semblent pas être la valeur de l'effort de restructuration de l'appel interne des mécanismes de résolution". C'est de la spéculation, bien sûr, mais il est au moins soutenus par des preuves, comme cette Déclaration (par l'une des deux personnes) dans le OpenJDK liste de diffusion:

"Je suppose que si final "par défaut" méthodes ont été autorisés, ils peuvent avoir besoin de réécriture à partir de l'intérieur invokespecial à l'utilisateur visible invokeinterface."

et les faits banals comme une méthode n'est tout simplement pas considéré comme pour être un (vraiment) méthode finale quand il s' default méthode, tel qu'il est actuellement mis en œuvre dans la Méthode: is_final_method méthode dans l'OpenJDK.

Plus vraiment "faisant autorité" de l'information est en effet difficile à trouver, même avec un nombre excessif de websearches et par la lecture de journaux. J'ai pensé qu'il pourrait être lié à des ambiguïtés potentielles lors de la résolution de la méthode de l'interface des appels avec l' invokeinterface enseignement et de classe et les appels de méthode, correspondant à l' invokevirtual enseignement: Pour l' invokevirtual d'instruction, il y a peut être un simple vtable de recherche, parce que la méthode doit être hérité d'une super-classe, ou mis en œuvre par la classe directement. En revanche, une invokeinterface d'appel doit examiner le site d'appel respective pour savoir qui de l'interface de cet appel, désigne en fait (ceci est expliqué plus en détail dans la InterfaceCalls page du HotSpot Wiki). Toutefois, final méthodes ne soit pas obtenir inséré dans la vtable , ou remplacer les entrées existantes dans la vtable (voir klassVtable.cpp. Ligne 333), et de même, les méthodes par défaut sont en train de remplacer les entrées existantes dans la vtable (voir klassVtable.cpp Ligne 202). Donc, la réelle raison (et donc, de la réponse) doit être cachée plus profond à l'intérieur de l' (assez complexe) appel de la méthode des mécanismes de résolution, mais peut-être que ces références seront néanmoins être considérée comme étant utile, ne serait-ce que pour les autres qui parviennent à tirer la réelle réponse.

4voto

skiwi Points 8321

Je ne pense pas qu'il est nécessaire de spécifier final sur un convienience la méthode de l'interface, je peux convenir cependant qu'il peut être utile, mais apparemment les coûts ont emporte sur les avantages.

Ce que vous êtes censé faire, de toute façon, c'est écrire des bon javadoc pour la méthode par défaut, montrant exactement ce que la méthode est et n'est pas autorisé à le faire. De cette façon, les classes implémentant l'interface "ne sont pas autorisés" pour changer la mise en œuvre, bien qu'il n'y a pas de garanties.

N'importe qui pourrait écrire un Collection qui adhère à l'interface, puis fait des choses dans les méthodes qui sont absolument contre-intuitif, il n'y a aucun moyen de vous protéger de cela, d'autres que l'écriture de vastes tests unitaires.

-3voto

MikeFHay Points 1201

Quelle est la raison de finale (et aussi static final) n'a jamais fait de Java 8 interfaces?

Eh bien, je peux répondre à la statique de la finale de peu au moins. Les méthodes statiques ne peuvent pas être remplacés, il n'ya donc pas besoin de préciser qu'ils sont en finale.

Cela peut aller d'une certaine façon à répondre à votre autre question aussi. Que les méthodes par défaut ne peut fonctionner que sur l'interface publique, ils peuvent tout aussi facilement être écrit que des méthodes statiques. Si vous pouvez obtenir un non-substituables méthode sur votre interface déjà, par l'écriture d'une méthode statique.

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