Muy buena pregunta. Para casi todas las demás cosas en Java, he encontrado una razón real para las decisiones tomadas, pero para esta no. Para mí tiene mucho sentido definir un método protegido en una interfaz que permite que otra clase dentro del mismo paquete use este método en un objeto de implementación sin necesidad de exponer ese método, que puede no estar destinado a ser llamado por nadie más que el miembros del paquete, al resto del mundo.
Markus A.
4
@MarkusA. Pero las interfaces funcionan en dos direcciones, es decir, también pueden ser implementadas por clases fuera del paquete actual (y luego quizás pasarse como argumentos a métodos dentro de este paquete). ¿Cómo podría una clase ajena al paquete actual implementar métodos "protegidos" de alguna interfaz pública?
MartinStettner
8
@MartinStettner: No lo haría. Ese sería el punto. Un paquete puede tener varias clases no relacionadas que implementan una interfaz y quieren garantizar a cualquier código que reciba una referencia de ese tipo de interfaz que se comportará de cierta manera. Tal garantía podría hacerse mucho más fuerte si se pudiera evitar que el código externo afirme implementar la interfaz mientras se comporta de manera contraria a su contrato.
si la interfaz tiene un protectedmétodo, todas las clases de implementación se verán como un subtipo de la interfaz. y todas estas clases PUEDEN acceder a métodos protegidos. ¿No hace que la protectedpalabra clave en el método sea inútil? mientras no tengamos ninguna forma de restringir quién implementa esta interfaz, la palabra clave protegida en el método es inútil. ¡corrígeme si me equivoco!
amarnath harish
Respuestas:
67
Porque se supone que una interfaz significa "lo que puedes ver desde fuera de la clase". No tendría sentido agregar métodos no públicos.
Pero, ¿por qué no tener funciones que solo los miembros del mismo paquete que la interfaz "puedan ver desde fuera de la clase"? He tenido varios casos de uso en los que deseaba esto.
Markus A.
5
@MarkusA. Me doy cuenta de que es tarde, pero luego puede hacer un completo abstract class, que es todo interface, y especificar el acceso que desee. Concedido, esto pierde el beneficio de múltiples implementaciones que se interfaceobtienen en Java, pero establecer honestamente un contrato que se adhiera a las limitaciones de algún otro paquete sería imposible de probar y confuso, ya que prácticamente no podría acceder al método de implementación de su propia implementación fuera de ese paquete. .
pickypg
10
@pickypg Pero si la clase que implementaría la interfaz ya extiende otra clase, no puede hacer que extienda otra clase. No lo encontraría confuso para una interfaz que se usa solo dentro de un paquete.
Flamma
24
@Raveline, -1, Esto plantea la pregunta "¿por qué se supone que una interfaz significa lo que puedes ver desde fuera de la clase?" Java 8 ya permite el cuerpo del método en las interfaces, así que ¿por qué no permitir también métodos abstractos protegidos?
Pacerier
8
A menudo leo esta explicación, pero en mi humilde opinión está mal. Una interfaz es una especie de "protocolo de intercambio estándar", sin importar si se trata de OOP, API de comunicación o hardware. El puerto USB de mi PC es claramente una interfaz pública. Pero los pines de mi placa base, que está detrás de una carcasa con llave, que proporcionan acceso a los puertos USB opcionales, son claramente una interfaz "protegida". Luego tenemos el chip BIOS, que también es una interfaz estandarizada, pero nunca se hace público de ninguna manera, solo unas pocas empresas conocen los detalles exactos en privado. Entonces, por supuesto, ¡las interfaces pueden tener cualquier visibilidad! ¿Por qué no en OOP?
Foo Bar
55
Aunque la razón citada a menudo es que "las interfaces definen las API públicas", creo que es una simplificación excesiva. (Y también "huele" a lógica circular).
No tendría sentido tener interfaces que tuvieran una mezcla de modificadores de acceso; por ejemplo, en parte pública y en parte restringida a otras clases en el mismo paquete que la interfaz. De hecho, en algunos casos esto podría ser muy útil, en mi opinión.
En realidad, creo que la parte del razonamiento detrás de hacer que los miembros de una interfaz sean implícitamente públicos es que hace que el lenguaje Java sea más simple :
Los miembros de la interfaz pública implícitamente son más fáciles de manejar para los programadores. ¿Cuántas veces ha visto código (clases) donde los modificadores de acceso al método se eligieron aparentemente al azar? Muchos programadores "normales" tienen dificultades para comprender la mejor forma de gestionar los límites de abstracción de Java 1 . Agregar público / protegido / paquete-privado a las interfaces hace que sea aún más difícil para ellos.
Los miembros de la interfaz pública implícitamente simplifican la especificación del lenguaje ... y, por lo tanto, la tarea para los escritores de compiladores de Java y las personas que implementan las API de Reflection.
La línea de pensamiento de que "las interfaces definen las API públicas" es posiblemente una consecuencia (o característica) de la decisión de simplificar el diseño del lenguaje ... no al revés. Pero en realidad, las dos líneas de pensamiento probablemente se desarrollaron en paralelo en la mente de los diseñadores de Java.
En cualquier caso, la respuesta oficial a la RFE en JDK-8179193 deja en claro que el equipo de diseño de Java decidió 2 que permitir las protectedinterfaces agrega complejidad para un beneficio real mínimo. Felicitaciones a @skomisa por encontrar la evidencia .
La evidencia en la RFE resuelve el problema. Esa es la razón oficial por la que no se ha agregado.
1 - Por supuesto, los programadores de primera no tienen dificultad con estas cosas y pueden agradecer una paleta más rica de funciones de control de acceso. Pero, ¿qué sucede cuando su código se entrega a otra persona para que lo mantenga?
2 - Puede que no esté de acuerdo con su decisión o con su razonamiento declarado, pero eso es discutible.
Debo decir que esta pregunta ha sido reabierta por la introducción de métodos predeterminados en Java 8. El proyecto en el que estoy trabajando ahora es, similar a la naturaleza básica de una interfaz, destinado a abstraer la intención de la implementación.
Hay varios casos en los que podría simplificar drásticamente mi código con un método "protegido por defecto". Resulta que eso en realidad no funciona, ya que las interfaces aún se adhieren a la lógica de Java 7. Un método protegido normal no tiene ningún sentido especialmente, por las razones mencionadas anteriormente; pero si un método público predeterminado requiere un recurso de bajo nivel que probablemente no cambiará y puede ser proporcionado por un método protegido, me parece que tener un trabajo "protegido por defecto" no solo mantendría un código más limpio, sino que protegería a los usuarios futuros de abusos accidentales.
(Trágicamente, esto no cambia el hecho de que todavía necesito complicar demasiado mi código con resúmenes innecesarios; pero tengo la intención de poner una solicitud de función en Oracle).
Estoy 100% de acuerdo. Las clases abstractas eran una alternativa sensata antes de la introducción de métodos predeterminados. Sin embargo, las limitaciones que imponen a la herencia múltiple significa que no son perfectas. Las interfaces con métodos predeterminados son normalmente una mejor alternativa en un mundo> = JDK 1.8, pero debido a que no pueden almacenar el estado, se basan en la definición de otros métodos abstractos para exponer el estado, lo que significa que el estado se hace público, que no siempre es lo que usted quiere.
P. Jeremy Krieg
10
Porque las interfaces definen API públicas. Todo lo que está protegido es un detalle interno que no pertenece a una interfaz.
Puede utilizar clases abstractas con métodos abstractos protegidos, pero las interfaces están restringidas a métodos públicos y campos finales estáticos públicos.
Dijiste "porque las interfaces definen las API públicas". Entonces, ¿cuál es la razón por la que las interfaces deberían definir solo publicAPI? Hay una diferencia entre "detalle interno" con "detalle de implementación", protecteden Java definitivamente no es un detalle interno ya que ahora es una interfaz pública publicada para todos los que pueden subclasificarla, que es básicamente todo el mundo.
Pacerier
1
Ya no es cierto con los métodos predeterminados de Java 8.
Mario Rossi
@MarioRossi Y tampoco es cierto con los métodos de interfaz privada de Java 9.
skomisa
7
Quizás, porque es una interfaz , es decir, está ahí para decirles a los clientes lo que pueden hacer con las instancias, en lugar de decirles lo que no pueden hacer.
No veo por qué una interfaz no podría decirle a las subclases lo que pueden hacer sin exponer esa implementación al mundo exterior. Esta fue una decisión de diseño que se tomó en un momento en que las clases abstractas podían usarse como una alternativa perfecta. Pero con el advenimiento de los métodos predeterminados en las interfaces, las clases abstractas son ahora una alternativa imperfecta.
P. Jeremy Krieg
6
Creo firmemente que las interfaces deberían permitir métodos protegidos; ¿Quién dijo que las interfaces deben ser visibles para todos en todo el mundo? En cuanto a su punto de que podría confundir a los programadores "ordinarios" (léase: incompetentes): gran parte de la programación orientada a objetos se trata de estructurar adecuadamente objetos, clases, paquetes, etc., si un programador tiene dificultades para hacer todo eso correctamente, tiene una un problema mucho mayor. Java fue construido para ese tipo de cosas.
Varias respuestas aquí emplean un razonamiento circular para explicar por qué los métodos de interfaz no se pueden proteger: es porque tienen que ser públicos, ¡así que obviamente no se pueden proteger!
Métodos protegidos en interfaces: compartir entre paquetes
Dado que los modificadores son un poco limitados en Java, una forma de compartir métodos entre paquetes está restringida a métodos públicos. A veces es peligroso hacer público un método, pero debe ser debido a la falta de modificadores adecuados. Mi solución supera esta limitación.
La especificación del lenguaje java no permite actualmente el modificador protegido para métodos de interfaz. Podemos aprovechar este hecho y utilizar protegido para métodos de interfaz para esta nueva función.
Si un método de interfaz está marcado como protegido y la interfaz es implementada por una clase en otro paquete, el método no necesitaría ser público, pero también podría ser privado o al menos protegido por paquete. El método es visible, lo que sea que la clase declare que es y además visible en el paquete fuente de la interfaz (¿y subpaquetes?).
De esta manera podríamos compartir ciertos métodos en paquetes bien conocidos.
Y esta es la respuesta a esa solicitud de mejora, que se cerró con estado Won't fix:
Esta propuesta intenta resolver un problema de una manera que agrega complejidad y casos especiales con poca ganancia real. Una forma típica de resolver este problema es tener una clase privada que implemente una interfaz pública. Los métodos de implementación son públicos, pero están dentro de una clase privada, por lo que permanecen privados.
Una alternativa disponible a partir de Java 9 es hacer públicas las clases y los métodos, pero dentro de un módulo que tiene una exportación calificada a módulos "amigos" específicos en lugar de exportarse al público en general.
Entonces, las conclusiones autorizadas de ese informe de error son:
La situación actual no va a cambiar; Es poco probable que las interfaces admitan protectedmétodos.
La justificación para no admitir protectedmétodos en interfaces es que " agrega complejidad y casos especiales con poca ganancia real ".
Desde Java 9, existe un enfoque alternativo para proporcionar acceso a los métodos a nivel de paquete. Utilice Java Platform Module System (JPMS) para " hacer públicos las clases y los métodos, pero dentro de un módulo que tiene una exportación calificada a módulos" amigos "específicos en lugar de exportarse al público en general ".
Dado que una clase de implementación debe implementar TODOS los métodos declarados en su interfaz, ¿qué pasaría si su clase de implementación estuviera en un paquete diferente?
Interfaz Si desea usar algo como lo que describió, continúe con clases abstractas o interfaces anidadas.
Un extracto del estilo de código sobre variables de interfaz, pero aún se aplica a los métodos:
Las variables de interfaz son implícitamente públicas porque las interfaces están destinadas a proporcionar una interfaz de programación de aplicaciones (API) que sea totalmente accesible para que los programadores de Java hagan referencia e implementen en sus propias aplicaciones. Dado que se puede usar una interfaz en paquetes de Java que son diferentes a los suyos, la visibilidad pública asegura que el código del programa pueda acceder a la variable.
Declarar subinterfaces internas es una buena práctica, pero no puede declarar sus métodos internos como protected técnicamente en una interfaz en Java.
Por supuesto, puede crear otra interfaz para uso interno que amplíe la interfaz pública:
Puede usar la InternalInterfaceinterfaz dentro del paquete, pero debe aceptar cualquier subtipo de PublicInterface(en métodos públicos):
package yourpackage;publicclassSomeClass{publicvoid someMethod(PublicInterface param){if(param instanceofInternalInterface){// run the optimized code}else{// run the general code}}}
Fuera del paquete los usuarios pueden utilizarlo PublicInterfacesin problemas.
Por lo general, los programadores crean clases abstractas en situaciones similares. Sin embargo, en este caso perdemos los beneficios de la herencia múltiple.
Fuera del paquete, los usuarios también pueden usar YourPublicInterface.Internal. Todo en una interfaz, incluidas las interfaces anidadas, es público independientemente de la presencia o ausencia de la publicpalabra clave.
Greg Roelofs
1
El único escenario en el que tendría sentido es cuando desea restringir la visibilidad al mismo paquete. Todos los demás usos de protectedno son aplicables. Específicamente, los protectedmétodos se utilizan a menudo para proporcionar acceso a algunos detalles de implementaciones de nivel inferior para descendientes. Pero declarar eso en una interfaz no tiene sentido, ya que no hay una implementación de nivel inferior para exponer.
E incluso el escenario del paquete no es realmente de lo que se tratan las interfaces.
Para lograr lo que probablemente desee, necesita dos interfaces, una para uso interno y otra que exponga en la API pública. (Con el interno posiblemente, pero no necesariamente extendiendo al público). O, como otros señalaron, una superclase abstracta.
Una superclase abstracta puede evitar ser derivada por tipos fuera de su paquete. Alguien que reciba una referencia de este tipo de superclase, que confíe en el autor del paquete, puede estar seguro de que el objeto se comportará como se indica. Si un paquete tiene varias clases que quieren exponer alguna funcionalidad común, pero no encajan en una jerarquía adecuada (por ejemplo, un implementa las funciones X e Y, una Y y Z, y una X y Z) sería útil si pudiera exponer la funcionalidad usando interfaces sin dejar de prometer que las instancias referidas por los tipos de interfaz serían "genuinas".
supercat
0
Los métodos protegidos siempre son accesibles por subclase solo si la subclase extiende la clase base.
En el caso de la interfaz, la subclase nunca extiende la interfaz. Implementa la interfaz.
Los métodos protegidos son accesibles a través de extender y no con implemento .
Las interfaces están destinadas a exponer métodos al mundo exterior . Por tanto, estos métodos son públicos por naturaleza. Sin embargo, si desea introducir abstracción dentro de la misma familia de clases , es posible crear otro nivel de abstracción entre su interfaz y la clase de implementación, es decir, una clase abstracta. A continuación se muestra un ejemplo.
publicinterfaceMyInterface{publicvoid publicMethod();// needs to be public}publicabstractclassMyAbstractClassimplementsMyInterface{@Overridepublicvoid publicMethod(){
protectedMethod();// you can call protected method here// do other stuff}protectedabstractvoid protectedMethod();// can be protected}publicclassMyClassextendsMyAbstractClass{@Overrideprotectedvoid protectedMethod(){// implement protected method here, without exposing it as public}}
Pero los métodos privados que nadie verá están permitidos en las interfaces.
Alex78191
java tiene métodos predeterminados en interfaces, es decir, una interfaz es una muleta para evitar la herencia múltiple de clases abstractas. Entonces, se permite la herencia múltiple de clases abstractas. Los conflictos de métodos predeterminados no se convirtieron en un problema.
Alex78191
Tienes razón. A partir de Java 9, se permiten métodos privados en las interfaces. Estos no pueden ser abstractos y se implementan y utilizan dentro de la interfaz, principalmente por otros métodos predeterminados o estáticos (si son estáticos ellos mismos).
Stefanos Kargas
1
Esta respuesta simplemente ignora la pregunta: ¿por qué las interfaces no pueden tener métodos protegidos? Los métodos protegidos seguirían "exponiendo métodos al mundo exterior" , y la afirmación de que "estos métodos son públicos por naturaleza" es simplemente falsa. Son públicos porque el lenguaje fue diseñado de esa manera, pero podría haber permitido métodos protegidos en interfaces. El OP simplemente pregunta por qué.
protected
método, todas las clases de implementación se verán como un subtipo de la interfaz. y todas estas clases PUEDEN acceder a métodos protegidos. ¿No hace que laprotected
palabra clave en el método sea inútil? mientras no tengamos ninguna forma de restringir quién implementa esta interfaz, la palabra clave protegida en el método es inútil. ¡corrígeme si me equivoco!Respuestas:
Porque se supone que una interfaz significa "lo que puedes ver desde fuera de la clase". No tendría sentido agregar métodos no públicos.
fuente
abstract class
, que es todointerface
, y especificar el acceso que desee. Concedido, esto pierde el beneficio de múltiples implementaciones que seinterface
obtienen en Java, pero establecer honestamente un contrato que se adhiera a las limitaciones de algún otro paquete sería imposible de probar y confuso, ya que prácticamente no podría acceder al método de implementación de su propia implementación fuera de ese paquete. .Aunque la razón citada a menudo es que "las interfaces definen las API públicas", creo que es una simplificación excesiva. (Y también "huele" a lógica circular).
No tendría sentido tener interfaces que tuvieran una mezcla de modificadores de acceso; por ejemplo, en parte pública y en parte restringida a otras clases en el mismo paquete que la interfaz. De hecho, en algunos casos esto podría ser muy útil, en mi opinión.
En realidad, creo que la parte del razonamiento detrás de hacer que los miembros de una interfaz sean implícitamente públicos es que hace que el lenguaje Java sea más simple :
Los miembros de la interfaz pública implícitamente son más fáciles de manejar para los programadores. ¿Cuántas veces ha visto código (clases) donde los modificadores de acceso al método se eligieron aparentemente al azar? Muchos programadores "normales" tienen dificultades para comprender la mejor forma de gestionar los límites de abstracción de Java 1 . Agregar público / protegido / paquete-privado a las interfaces hace que sea aún más difícil para ellos.
Los miembros de la interfaz pública implícitamente simplifican la especificación del lenguaje ... y, por lo tanto, la tarea para los escritores de compiladores de Java y las personas que implementan las API de Reflection.
La línea de pensamiento de que "las interfaces definen las API públicas" es posiblemente una consecuencia (o característica) de la decisión de simplificar el diseño del lenguaje ... no al revés. Pero en realidad, las dos líneas de pensamiento probablemente se desarrollaron en paralelo en la mente de los diseñadores de Java.
En cualquier caso, la respuesta oficial a la RFE en JDK-8179193 deja en claro que el equipo de diseño de Java decidió 2 que permitir las
protected
interfaces agrega complejidad para un beneficio real mínimo. Felicitaciones a @skomisa por encontrar la evidencia .La evidencia en la RFE resuelve el problema. Esa es la razón oficial por la que no se ha agregado.
1 - Por supuesto, los programadores de primera no tienen dificultad con estas cosas y pueden agradecer una paleta más rica de funciones de control de acceso. Pero, ¿qué sucede cuando su código se entrega a otra persona para que lo mantenga?
2 - Puede que no esté de acuerdo con su decisión o con su razonamiento declarado, pero eso es discutible.
fuente
Debo decir que esta pregunta ha sido reabierta por la introducción de métodos predeterminados en Java 8. El proyecto en el que estoy trabajando ahora es, similar a la naturaleza básica de una interfaz, destinado a abstraer la intención de la implementación.
Hay varios casos en los que podría simplificar drásticamente mi código con un método "protegido por defecto". Resulta que eso en realidad no funciona, ya que las interfaces aún se adhieren a la lógica de Java 7. Un método protegido normal no tiene ningún sentido especialmente, por las razones mencionadas anteriormente; pero si un método público predeterminado requiere un recurso de bajo nivel que probablemente no cambiará y puede ser proporcionado por un método protegido, me parece que tener un trabajo "protegido por defecto" no solo mantendría un código más limpio, sino que protegería a los usuarios futuros de abusos accidentales.
(Trágicamente, esto no cambia el hecho de que todavía necesito complicar demasiado mi código con resúmenes innecesarios; pero tengo la intención de poner una solicitud de función en Oracle).
fuente
Porque las interfaces definen API públicas. Todo lo que está protegido es un detalle interno que no pertenece a una interfaz.
Puede utilizar clases abstractas con métodos abstractos protegidos, pero las interfaces están restringidas a métodos públicos y campos finales estáticos públicos.
fuente
public
API? Hay una diferencia entre "detalle interno" con "detalle de implementación",protected
en Java definitivamente no es un detalle interno ya que ahora es una interfaz pública publicada para todos los que pueden subclasificarla, que es básicamente todo el mundo.Quizás, porque es una interfaz , es decir, está ahí para decirles a los clientes lo que pueden hacer con las instancias, en lugar de decirles lo que no pueden hacer.
fuente
Creo firmemente que las interfaces deberían permitir métodos protegidos; ¿Quién dijo que las interfaces deben ser visibles para todos en todo el mundo? En cuanto a su punto de que podría confundir a los programadores "ordinarios" (léase: incompetentes): gran parte de la programación orientada a objetos se trata de estructurar adecuadamente objetos, clases, paquetes, etc., si un programador tiene dificultades para hacer todo eso correctamente, tiene una un problema mucho mayor. Java fue construido para ese tipo de cosas.
fuente
Varias respuestas aquí emplean un razonamiento circular para explicar por qué los métodos de interfaz no se pueden proteger: es porque tienen que ser públicos, ¡así que obviamente no se pueden proteger!
Eso no explica nada, pero afortunadamente alguien planteó una solicitud de mejora para métodos protegidos en interfaces como un error de JDK hace un par de años, lo que arroja algo de luz sobre el problema:
Y esta es la respuesta a esa solicitud de mejora, que se cerró con estado
Won't fix
:Entonces, las conclusiones autorizadas de ese informe de error son:
protected
métodos.protected
métodos en interfaces es que " agrega complejidad y casos especiales con poca ganancia real ".fuente
Dado que una clase de implementación debe implementar TODOS los métodos declarados en su interfaz, ¿qué pasaría si su clase de implementación estuviera en un paquete diferente?
fuente
Interfaz Si desea usar algo como lo que describió, continúe con clases abstractas o interfaces anidadas.
Un extracto del estilo de código sobre variables de interfaz, pero aún se aplica a los métodos:
fuente
Declarar subinterfaces internas es una buena práctica, pero no puede declarar sus métodos internos como
protected
técnicamente en una interfaz en Java.Por supuesto, puede crear otra interfaz para uso interno que amplíe la interfaz pública:
Puede usar la
InternalInterface
interfaz dentro del paquete, pero debe aceptar cualquier subtipo dePublicInterface
(en métodos públicos):Fuera del paquete los usuarios pueden utilizarlo
PublicInterface
sin problemas.Por lo general, los programadores crean clases abstractas en situaciones similares. Sin embargo, en este caso perdemos los beneficios de la herencia múltiple.
fuente
YourPublicInterface.Internal
. Todo en una interfaz, incluidas las interfaces anidadas, es público independientemente de la presencia o ausencia de lapublic
palabra clave.El único escenario en el que tendría sentido es cuando desea restringir la visibilidad al mismo paquete. Todos los demás usos de
protected
no son aplicables. Específicamente, losprotected
métodos se utilizan a menudo para proporcionar acceso a algunos detalles de implementaciones de nivel inferior para descendientes. Pero declarar eso en una interfaz no tiene sentido, ya que no hay una implementación de nivel inferior para exponer.E incluso el escenario del paquete no es realmente de lo que se tratan las interfaces.
Para lograr lo que probablemente desee, necesita dos interfaces, una para uso interno y otra que exponga en la API pública. (Con el interno posiblemente, pero no necesariamente extendiendo al público). O, como otros señalaron, una superclase abstracta.
fuente
Los métodos protegidos siempre son accesibles por subclase solo si la subclase extiende la clase base.
En el caso de la interfaz, la subclase nunca extiende la interfaz. Implementa la interfaz.
Los métodos protegidos son accesibles a través de extender y no con implemento .
fuente
Las interfaces están destinadas a exponer métodos al mundo exterior . Por tanto, estos métodos son públicos por naturaleza. Sin embargo, si desea introducir abstracción dentro de la misma familia de clases , es posible crear otro nivel de abstracción entre su interfaz y la clase de implementación, es decir, una clase abstracta. A continuación se muestra un ejemplo.
fuente