Protégé dans les interfaces

111

Pourquoi toutes les méthodes sont-elles interfaceimplicitement dans une définition public? Pourquoi n'autorise-t-il pas une protectedméthode?

Swaranga Sarma
la source
22
Très bonne question. Pour presque toutes les autres choses en Java, j'ai trouvé une vraie raison pour les choix effectués, mais pour celle-ci, je n'ai pas. Il est parfaitement logique pour moi de définir une méthode protégée dans une interface qui permet à une autre classe à l'intérieur du même package d'utiliser cette méthode sur un objet d'implémentation sans avoir besoin d'exposer cette méthode, qui peut ne pas être censée être appelée par quelqu'un d'autre que le membres du package, vers le reste du monde.
Markus A.
4
@MarkusA. Mais les interfaces fonctionnent dans les deux sens, c'est-à-dire qu'elles peuvent également être implémentées par des classes en dehors du package courant (et peut-être ensuite passées comme arguments aux méthodes à l'intérieur de ce package). Comment une classe extérieure au package actuel pourrait-elle implémenter des méthodes "protégées" d'une interface publique?
MartinStettner
8
@MartinStettner: Ce ne serait pas le cas. Ce serait le point. Un package peut avoir plusieurs classes non liées qui implémentent une interface, et veulent garantir à tout code recevant une référence de ce type d'interface qu'il se comportera d'une certaine manière. Une telle garantie pourrait être rendue beaucoup plus forte si le code extérieur pouvait être empêché de prétendre implémenter l'interface tout en se comportant d'une manière contraire à son contrat.
supercat
1
@MarkusA. vous avez soulevé un bon point, vous devriez pouvoir y parvenir avec le système de modules de Java 9
Nir Alfasi
1
si l'interface a une protectedméthode, toute classe d'implémentation sera considérée comme un sous-type de l'interface. et toutes ces classes PEUVENT accéder aux méthodes protégées. cela ne rend-il pas protectedinutile le mot-clé sur la méthode? tant que nous n'avons aucun moyen de restreindre qui implémente ce mot-clé protégé par l' interface sur la méthode est inutile. Corrige moi si je me trompe!
amarnath harish

Réponses:

67

Parce qu'une interface est censée signifier "ce que vous pouvez voir de l'extérieur de la classe". Il ne serait pas logique d'ajouter des méthodes non publiques.

Raveline
la source
16
Mais pourquoi ne pas avoir des fonctions que seuls les membres du même package que l'interface "peuvent voir de l'extérieur de la classe"? J'ai eu plusieurs cas d'utilisation où je souhaitais cela.
Markus A.
5
@MarkusA. Je me rends compte que c'est tard, mais alors vous pouvez faire un complètement abstract class, ce qui est tout ce qui est interface, et spécifier l'accès que vous voulez. Certes, cela perd le bénéfice de plusieurs implémentations disponibles interfaceen Java, mais établir honnêtement un contrat qui respecte les limitations d'un autre package serait impossible à tester et déroutant, car vous ne seriez pratiquement pas en mesure d'accéder à la méthode de votre propre implémentation en dehors de ce package. .
pickypg
10
@pickypg Mais si la classe qui implémenterait l'interface étend déjà une autre classe, vous ne pouvez pas la faire étendre une autre classe. Je ne trouverais pas cela déroutant pour une interface qui n'est utilisée que dans un package.
Flamma
24
@Raveline, -1, Cela pose la question "pourquoi une interface est-elle censée signifier ce que vous pouvez voir de l'extérieur de la classe?" Java 8 autorise déjà le corps de méthode dans les interfaces, alors pourquoi ne pas autoriser également les méthodes abstraites protégées?
Pacerier
8
Je lis souvent cette explication, mais c'est faux à mon humble avis. Une interface est une sorte de "protocole d'échange standard", qu'il s'agisse de POO, d'API de communication ou de matériel. Le port USB de mon PC est clairement une interface publique. Mais les broches sur ma carte mère, qui se trouve derrière un boîtier verrouillé par clé, qui donnent accès aux ports USB optionnels sont clairement une interface "protégée". Ensuite, nous avons la puce BIOS - qui est également une interface standardisée, mais elle n'est jamais rendue publique en aucune façon, seules quelques entreprises connaissent les détails exacts en privé. Alors, bien sûr, les interfaces peuvent avoir n'importe quelle visibilité! Pourquoi pas en POO?
Foo Bar
55

Bien que la raison souvent citée soit que "les interfaces définissent les API publiques", je pense que c'est une simplification excessive. (Et ça «sent» aussi la logique circulaire.)

Il ne serait pas inutile d'avoir des interfaces qui ont un mélange de modificateurs d'accès; par exemple en partie public et en partie restreint à d'autres classes dans le même package que l'interface. En fait, dans certains cas, cela pourrait être utile en bas à droite, OMI.

En fait, je pense que le raisonnement derrière la publication implicite des membres d'une interface est que cela simplifie le langage Java :

  • Les membres de l'interface implicitement publics sont plus simples à gérer pour les programmeurs. Combien de fois avez-vous vu du code (classes) où les modificateurs d'accès aux méthodes ont été choisis apparemment au hasard? De nombreux programmeurs «ordinaires» ont du mal à comprendre comment gérer au mieux les limites d'abstraction Java 1 . L'ajout de public / protected / package-private aux interfaces rend la tâche encore plus difficile pour elles.

  • Implicitement, les membres de l'interface publique simplifient la spécification du langage ... et donc la tâche des rédacteurs du compilateur Java et des personnes qui implémentent les API Reflection.

La ligne de pensée selon laquelle les "interfaces définissent les API publiques" est sans doute une conséquence (ou caractéristique) de la décision de simplification de la conception du langage ... et non l'inverse. Mais en réalité, les deux lignes de pensée se sont probablement développées en parallèle dans l'esprit des concepteurs de Java.

Quoi qu'il en soit, la réponse officielle à la RFE dans JDK-8179193 indique clairement que l'équipe de conception Java a décidé 2 que permettreprotected les interfaces ajoute de la complexité pour peu d'avantages réels. Félicitations à @skomisa pour avoir trouvé les preuves .

Les preuves contenues dans la RFE règlent la question. C'est la raison officielle pour laquelle cela n'a pas été ajouté.


1 - Bien sûr, les programmeurs de haut niveau n'ont aucune difficulté avec ces choses, et peuvent accueillir une palette plus riche de fonctionnalités de contrôle d'accès. Mais que se passe-t-il lorsque leur code est remis à quelqu'un d'autre pour qu'il le maintienne?

2 - Vous pouvez être en désaccord avec leur décision ou leur raisonnement, mais c'est sans objet.

Stephen C
la source
21

Je dois dire que cette question a été rouverte par l'introduction de méthodes par défaut dans Java 8. Le projet sur lequel je travaille actuellement est, similaire à la nature de base d'une interface, destiné à abstraction de l'intention de l'implémentation.

Il y a plusieurs cas dans lesquels je pourrais considérablement simplifier mon code avec une méthode "protégée par défaut". Il s'avère que cela ne fonctionne pas réellement, car les interfaces restent fidèles à la logique Java 7. Une méthode protégée normale n'a aucun sens, pour les raisons mentionnées ci-dessus; mais si une méthode publique par défaut nécessite une ressource de bas niveau qui ne changera probablement pas et peut être fournie par une méthode protégée, il me semble qu'avoir un travail "protégé par défaut" ne maintiendrait pas seulement un code plus propre, cela protégerait les futurs utilisateurs de abus accidentels.

(Cela ne change pas tragiquement le fait que je dois encore trop compliquer mon code avec des résumés autrement inutiles; mais j'ai l'intention de mettre une demande de fonctionnalité chez Oracle.)

Michael Oberlin
la source
Je suis d'accord à 100%. Les classes abstraites étaient une alternative judicieuse avant l'introduction des méthodes par défaut. Cependant, les limitations qu'ils imposent à l'héritage multiple signifient qu'ils ne sont pas parfaits. Les interfaces avec les méthodes par défaut sont normalement une meilleure alternative dans un monde> = JDK 1.8, mais comme elles ne peuvent pas stocker l'état, elles dépendent de la définition d'autres méthodes abstraites pour exposer l'état, ce qui signifie que l'état est rendu public, ce qui n'est pas toujours ce que tu veux.
Père Jeremy Krieg
10

Parce que les interfaces définissent les API publiques. Tout ce qui est protégé est un détail interne qui n'appartient pas à une interface.

Vous pouvez utiliser des classes abstraites avec des méthodes abstraites protégées, mais les interfaces sont limitées aux méthodes publiques et aux champs finaux statiques publics.

Sean Patrick Floyd
la source
5
Vous avez déclaré "parce que les interfaces définissent les API publiques". Alors, quelle est la raison pour laquelle les interfaces ne devraient définir que des publicAPI? Il y a une différence entre «détail interne» et «détail d'implémentation», protecteden Java ce n'est certainement pas un détail interne car c'est maintenant une interface publique publiée pour tous ceux qui peuvent le sous-classer, ce qui est fondamentalement le monde entier.
Pacerier
1
Ce n'est plus vrai avec les méthodes par défaut de Java 8.
Mario Rossi
@MarioRossi Et ce n'est plus vrai non plus avec les méthodes d'interface privée de Java 9.
skomisa
7

Peut-être parce que c'est une interface , c'est-à-dire qu'il est là pour dire aux clients ce qu'ils peuvent faire avec des instances, plutôt que pour leur dire ce qu'ils ne peuvent pas faire.

Ingo
la source
1
Je ne vois pas pourquoi une interface ne pourrait pas également dire aux sous-classes ce qu'elles peuvent faire sans exposer cette implémentation au monde extérieur. C'était une décision de conception qui a été prise à une époque où les classes abstraites pouvaient être utilisées comme une alternative parfaite. Mais avec l'avènement des méthodes par défaut dans les interfaces, les classes abstraites sont désormais une alternative imparfaite.
Père Jeremy Krieg
6

Je pense fermement que les interfaces devraient permettre des méthodes protégées; Qui a dit que les interfaces doivent être visibles de tous dans le monde entier? Quant à votre argument selon lequel cela pourrait confondre les programmeurs "ordinaires" (lire: incompétents): Une grande partie de la POO concerne la structuration correcte des objets, des classes, des packages, etc., si un programmeur a du mal à faire tout cela correctement, il a un problème beaucoup plus important. Java a été conçu pour ce type de chose.

IntelliData
la source
Cela ne répond pas à la question.
Stephen C
5

Plusieurs réponses ici utilisent un raisonnement circulaire pour expliquer pourquoi les méthodes d'interface ne peuvent pas être protégées: c'est parce qu'elles doivent être publiques, donc évidemment elles ne peuvent pas être protégées!

Cela n'explique rien, mais heureusement, quelqu'un a soulevé une demande d'amélioration des méthodes protégées dans les interfaces en tant que bogue JDK il y a quelques années, ce qui éclaire un peu le problème:

Méthodes protégées dans les interfaces: partager entre les packages

Étant donné que les modificateurs sont un peu limités en Java, un moyen de partager des méthodes entre des packages est limité aux méthodes publiques. Parfois, il est dangereux de rendre une méthode publique, mais cela doit être dû au manque de modificateurs appropriés. Ma solution surmonte cette limitation.

La spécification du langage Java n'autorise actuellement pas le modificateur protected pour les méthodes d'interface. Nous pouvons profiter de ce fait et utiliser des méthodes d'interface protégées pour cette nouvelle fonctionnalité.

Si une méthode d'interface est marquée comme protégée et que l'interface est implémentée par une classe dans un autre package, la méthode n'aurait pas besoin d'être publique, mais pourrait également être privée ou au moins protégée par un package. La méthode est visible, ce que la classe déclare être et en plus visible dans le paquet source de l'interface (et les sous-packages?).

De cette façon, nous pourrions partager certaines méthodes dans des packages bien connus.

Et voici la réponse à cette demande d'amélioration, qui a été clôturée avec le statut Won't fix:

Cette proposition tente de résoudre un problème d'une manière qui ajoute de la complexité et des cas spéciaux pour peu de gain réel. Une manière typique de résoudre ce problème est d'avoir une classe privée qui implémente une interface publique. Les méthodes d'implémentation sont publiques, mais se trouvent dans une classe privée, elles restent donc privées.

Une alternative disponible à partir de Java 9 est de rendre les classes et les méthodes publiques, mais dans un module qui a une exportation qualifiée vers des modules "amis" spécifiques au lieu d'être exportés vers le grand public.

Les points à retenir de ce rapport de bogue sont donc:

  • La situation actuelle ne va pas changer; Il est peu probable que les interfaces prennent en charge les protectedméthodes.
  • La justification de ne pas prendre en charge les protectedméthodes dans les interfaces est que cela « ajoute de la complexité et des cas spéciaux pour un gain réel minime ».
  • Depuis Java 9, il existe une approche alternative pour fournir un accès au niveau du package aux méthodes. Utilisez le Java Platform Module System (JPMS) pour " rendre les classes et les méthodes publiques, mais dans un module qui a une exportation qualifiée vers des modules" amis "spécifiques au lieu d'être exportés vers le grand public ".
skomisa
la source
4

Puisqu'une classe d'implémentation doit implémenter TOUTES les méthodes déclarées dans votre interface, que se passerait-il si votre classe d'implémentation était dans un package différent?

dm76
la source
2

Interface Si vous voulez utiliser quelque chose comme vous l'avez décrit, continuez avec des classes abstraites ou des interfaces imbriquées.

Un extrait du style de code sur les variables d'interface, mais qui s'applique toujours aux méthodes:

Les variables d'interface sont implicitement publiques car les interfaces sont destinées à fournir une interface de programmation d'application (API) entièrement accessible aux programmeurs Java pour la référence et l'implémentation dans leurs propres applications. Puisqu'une interface peut être utilisée dans des packages Java différents des leurs, la visibilité publique garantit que le code du programme peut accéder à la variable.
grizzly
la source
2

Déclarer des sous- protectedinterfaces internes est une bonne pratique, mais vous ne pouvez pas déclarer vos méthodes internes comme dans une interface en Java, techniquement.

Bien sûr, vous pouvez créer une autre interface à usage interne qui étend l'interface publique:

package yourpackage;

public interface PublicInterface {

    public void doThing1();

    public void doThing2();

    public void doThing3();

}

package yourpackage;

interface InternalInterface extends PublicInterface {

    void doAnyInternalThing1();

    void doAnyInternalThing2();

}

Vous pouvez utiliser l' InternalInterfaceinterface à l'intérieur du package, mais vous devez accepter tout sous-type de PublicInterface(dans les méthodes publiques):

package yourpackage;

public class SomeClass {

    public void someMethod(PublicInterface param) {
        if (param instanceof InternalInterface) {
            // run the optimized code
        } else {
            // run the general code
        }
    }

}

En dehors du package, les utilisateurs peuvent utiliser PublicInterfacesans problème.

Les programmeurs créent généralement des classes abstraites dans des situations similaires. Cependant, dans ce cas, nous perdons les avantages de l'héritage multiple.

Dávid Horváth
la source
1
En dehors du package, les utilisateurs peuvent également utiliser YourPublicInterface.Internal. Tout dans une interface, y compris les interfaces imbriquées, est public quelle que soit la présence ou l'absence du publicmot - clé.
Greg Roelofs
1

Le seul scénario où cela aurait du sens est celui où vous souhaitez restreindre la visibilité au même package. Toutes les autres utilisations de protectedne sont pas applicables. Plus précisément, les protectedméthodes sont souvent utilisées pour donner accès à certains détails des implémentations de niveau inférieur pour les descendants. Mais déclarer cela dans une interface n'a pas de sens, car il n'y a pas d'implémentation de niveau inférieur à exposer.

Et même le scénario de package n'est pas vraiment ce que sont les interfaces.

Pour réaliser ce que vous souhaitez probablement, vous avez besoin de deux interfaces, une à usage interne et une que vous exposez dans l'API publique. (Avec l'interne peut-être, mais pas nécessairement étendre le public.) Ou, comme d'autres l'ont souligné, une superclasse abstraite.

biziclop
la source
Une superclasse abstraite peut s'empêcher d'être dérivée par des types en dehors de son package. Quelqu'un recevant une référence d'un tel type de superclasse, qui fait confiance à l'auteur du package, peut être assuré que l'objet se comportera comme indiqué. Si un paquet a plusieurs classes qui veulent exposer certaines fonctionnalités communes, mais ne correspondent pas à une hiérarchie appropriée (par exemple, un implémentation des fonctions X et Y, un Y et Z, et un X et Z), il serait utile s'il pouvait exposer la fonctionnalité utilisant des interfaces tout en promettant que les instances référencées par les types d'interface seraient «authentiques».
supercat
0

Les méthodes protégées sont toujours accessibles par sous-classe uniquement si la sous-classe étend la classe de base.

En cas d'interface, la sous-classe n'étend jamais l'interface. Il implémente l'interface.

Les méthodes protégées sont accessibles via extend et non avec un outil .

Aftaab Siddiki
la source
quelle différence quel mot-clé, peu importe.
Alex78191
0

Les interfaces sont destinées à exposer les méthodes au monde extérieur . Ainsi, ces méthodes sont publiques par nature. Cependant, si vous voulez introduire l' abstraction dans la même famille de classes, c'est possible en créant un autre niveau d'abstraction entre votre interface et la classe d'implémentation, c'est-à-dire une classe abstraite. Un exemple est présenté ci-dessous.

public interface MyInterface {
    public void publicMethod(); // needs to be public
}

public abstract class MyAbstractClass implements MyInterface {
    @Override
    public void publicMethod() {
        protectedMethod(); // you can call protected method here
        // do other stuff
    }
    protected abstract void protectedMethod(); // can be protected
}

public class MyClass extends MyAbstractClass {
    @Override
    protected void protectedMethod() {
        // implement protected method here, without exposing it as public
    }
}
Stefanos Kargas
la source
2
Mais les méthodes privées que personne ne verra sont autorisées dans les interfaces.
Alex78191
java a des méthodes par défaut dans les interfaces, c'est-à-dire qu'une interface est une béquille pour contourner l'héritage multiple des classes abstraites. Laissez alors l'héritage multiple de classes abstraites est autorisé. Les conflits de méthodes par défaut ne sont pas devenus un problème.
Alex78191
Vous avez raison. Depuis Java 9, les méthodes privées sont autorisées dans les interfaces. Celles-ci ne peuvent pas être abstraites et sont implémentées et utilisées dans l'interface, principalement par d'autres méthodes par défaut ou statiques (si elles sont elles-mêmes statiques).
Stefanos Kargas
1
Cette réponse ignore simplement la question posée: pourquoi les interfaces ne peuvent-elles pas avoir de méthodes protégées? Les méthodes protégées «exposeraient encore les méthodes au monde extérieur» , et l'affirmation selon laquelle «ces méthodes sont publiques par nature» est tout simplement fausse. Ils sont publics parce que le langage a été conçu de cette façon, mais il aurait pu autoriser des méthodes protégées dans les interfaces. Le PO demande simplement pourquoi.
skomisa