¿Por qué Java no permite miembros privados en la interfaz?

Respuestas:

85

Desde Java Language Spec, (Control de acceso) :

"El lenguaje de programación Java proporciona mecanismos para el control de acceso, para evitar que los usuarios de un paquete o clase dependan de detalles innecesarios de la implementación de ese paquete o clase".

El control de acceso consiste en ocultar los detalles de implementación. Una interfaz no tiene ninguna implementación que ocultar.

Matten
fuente
9
Como podemos poner clases de nido dentro de una interfaz, podemos poner la implementación en la interfaz. Hacerlo está muy mal, pero podemos.
emory
28
Java 9 permite métodos privados en la interfaz, es lógico después de la adición de métodos predeterminados, Ref: bugs.openjdk.java.net/browse/JDK-8071453
Hariharan
3
"Hacerlo está muy mal" ... como siempre, depende del contexto.
JacksOnF1re
5
No es tan malo como parece. Los métodos privados en una interfaz solo pueden ser accesibles por métodos predeterminados en esa misma interfaz. Uno de los beneficios es ayudar a dividir la implementación de métodos predeterminados en funciones significativas más pequeñas sin romper la encapsulación.
Henry Pham
48

En Java 9, los métodos privados en las interfaces son posibles.

Especificaciones de Java 9

El equipo del compilador de javac se complace en anunciar la disponibilidad del soporte del compilador para métodos privados en interfaces que comienzan con la compilación 9 b54 de JDK.

chiperortiz
fuente
10
@SebiSebi, El momento en que te das cuenta de que Java es un lenguaje en vivo.
Arashsoft
@Arashsoft, OP solicita campos.
Pacerier
19

Los métodos de interfaz privada son parte de Java 9 como parte de JEP-213 . Dado que las interfaces en Java 8 pueden tener métodos predeterminados , los métodos privados permiten que varios métodos predeterminados utilicen un método privado compartido.

mkobit
fuente
13

A partir de Java 8, las interfaces pueden tener métodos predeterminados, y a partir de Java 9, se permite que una interfaz tenga métodos privados a los que solo se puede acceder mediante métodos predeterminados en la misma interfaz.

Peter Lawrey
fuente
Es bueno conocer las características de la interfaz Java-9.
Ravindra babu
9

Una interfaz se usa para describir una API que es proporcionada por cualquier clase que implemente la interfaz. Dado que una interfaz de su definición no tiene estado, no tiene sentido declarar miembros de campo en ella.

giorashc
fuente
En Java Land, un miembro es un campo, método, constructor o clase.
emory
7

No habría forma de implementar tal interfaz. Una respuesta a una pregunta que planteé sugiere fuertemente que sería imposible (sin cambiar radicalmente las reglas) implementar una interfaz con métodos privados; esto deja abierta la pregunta de por qué no se permiten los métodos privados protegidos y los paquetes.

class OuterClass
{
     void run ( MyInterface x )
     {
           x . publicMethod ( ) ;  // why not?
           x . protectedMethod ( ) ; // why not?
           x . packagePrivateMethod ( ) ; // why not?
           x . privateMethod ( ) ; // why not?
     }

     interface MyInterface
     {
           public abstract void publicMethod ( ) ; // OK

           protected abstract void protectedMethod ( ) ; // why not?

           abstract void packagePrivateMethod ( ) ; // in interface default is public, but why not package private

           private void privateMethod ( ) ; // impossible to implement
     }

     class MyImpl implements MyInterface
     {
           public void publicMethod ( ) { } // ok

           protected void protectedMethod ( ) { } // no sweat

           void packagePrivateMethod ( ) { } // no sweat

           private void privateMethod ( ) { } // not happening
     }
}

El siguiente código debería lograr el resultado deseado. Aunque todos los métodos son públicos, solo el método público es efectivamente público. El método protegido está efectivamente protegido. packagePrivateMethod es efectivamente packagePrivate. privateMethod es efectivamente privado.

class WorkAround
{
     void run ( MyPrivateInterface x )
     {
           x . publicMethod ( ) ;  
           x . protectedMethod ( ) ; 
           x . packagePrivateMethod ( ) ; 
           x . privateMethod ( ) ; 
     }

     public interface MyPublicInterface { void publicMethod ( ) ; }

     protected interface MyProtectedInterface extends MyPublicInterface { void protectedMethod ( ) ; }

     interface MyPackagePrivateInterface extends MyProtectedInterface { void packagePrivateMethod ( ) ; }

     private interface MyPrivateInterface extends MyPackagePrivateInterface { void privateMethod ( ) ; }
}
emory
fuente
6

Según el Javalenguaje de programación, el alcance del private membersestá limitado al classen el que se declara y solo se puede acceder a él mediante métodos de ese class. Pero intefaceno tiene un cuerpo de método, por lo tanto, no sirve de nada declarar miembros privados dentro de un interface.

Nishant
fuente
4

Java permite métodos privados en una interfaz en Java 9 . Los métodos predeterminados se introdujeron en Java 8. Es posible que varios métodos predeterminados quieran compartir algún código, entonces este código se puede mover a un método privado sin exponerlo al mundo exterior. Este error se ha corregido y, a partir de JDK 9 build 54, se ha resucitado el soporte del compilador para métodos de interfaz privada.

public interface IData{
   default void processData(int data) {
      validate(data);
      // do some work with it
   }
   default void consumeData(int data) {
      validate(data);
      // do some work with it
   }
   private void validate(int data) {
     // validate data
   }
}
akhil_mittal
fuente
3

Es porque serían inútiles.

No habría forma de llamar a un método privado.

Los miembros privados son un detalle de implementación. Una interfaz trata sobre el rol público que puede asumir una clase.

WW.
fuente
No estoy de acuerdo con "No habría forma de llamar a un método privado". Con las clases internas, habría una manera - stackoverflow.com/a/10169894/348975
emory
Considere los métodos predeterminados de java 8. La interfaz I tiene métodos predeterminados A y B con mucho código común. Para refactorizar esto, querrá el método C que contenga solo el código compartido y sea llamado por A y B. En Java 8, este sería un método predeterminado que está expuesto a todos los implementadores de interfaz. en Java 9 C podría ser un método privado que solo defecto métodos dentro I.
Ivan Krylov
2

los campos privados no serían completamente inútiles ya que otros campos y clases internas podrían acceder a ellos.

Sin embargo, los métodos privados no se pudieron implementar, incluso en clases anidadas, haciéndolos casi inútiles. Podrías leerlos usando la reflexión, pero eso es más bien un caso marginal.

Peter Lawrey
fuente
Perdón por excavar tumba aquí :( ¿Cómo funciona docs.oracle.com/javase/7/docs/api/java/io/Serializable.html en este caso? ¿La gente no puede implementarlo y luego sobrescribir los métodos readObject y writeObject ? Estoy seguro de que me estoy perdiendo algo
PatrickWalker
1

Los miembros privados no tienen sentido en la interfaz. La interfaz es una forma de acceder a una clase con métodos definidos en la que no es necesario ver el interior de esa clase.

Los miembros privados no están de acuerdo con eso.

juergen d
fuente
0

Los miembros de una clase que se declaran privados no son heredados por subclases de esa clase. Solo los miembros de una clase que están declarados protegidos o públicos son heredados por subclases declaradas en un paquete diferente al que se declara la clase.

Fuente

Entonces, no tiene ningún método de trabajo en una interfaz que pueda funcionar con ese campo privado no heredable. Entonces, ¿por qué debería existir?

Alireza Mohamadi
fuente
0

Sí, no puedo hacer eso. Para todos aquellos que comentan por qué no debería:

Imagine que tengo la clase A, que utiliza la interfaz I.La clase B, extiende la clase A, por lo tanto, también hereda todos los métodos de interfaz en A.

Ahora, imagine que quiero un método privado en la Clase A, pero también lo quiero definido contractualmente para otras clases (tal vez una clase C, que no necesariamente extiende la Clase B o A).

Quizás para un método de "inicialización", que quiero para todas las clases que usan una interfaz I. Pero, obviamente, no quiero que un método de inicialización sea público ... ya que solo debe usarse una vez, o como la clase lo considere necesario, no solo porque quiera usarlo todo.

La única solución es una solución alternativa, o simplemente forzando el método init en las clases mismas sin una interfaz.

No entiendo la razón también, seguro, pero aún así, a veces puede ser útil. Claramente, Oracle está de acuerdo, ya que permiten métodos de interfaz privados en JDK 9.

Lo que hice, para el mío de todos modos, fue colocar una variable booleana simple, de esa manera el método de interfaz (que debería ser privado) se puede marcar como verdadero (inicializado = verdadero) después de establecerse una vez. Luego, cuando se vuelve a llamar, el método simplemente no hace nada. De esta manera, el método de la interfaz se puede implementar como público, pero como el constructor (de mi clase) llama al método primero, esto establece la variable en verdadera, por lo que no se puede volver a llamar.

De lo contrario, tendría que probar una solución alternativa diferente si solo desea que el funcionamiento interno de la clase lo use ... quizás un método en sí mismo activa y desactiva una bandera a medida que lo usa. Cuando la bandera es falsa, el método no hace nada (esto sería cuando alguien lo llama desde fuera de la clase). Sin embargo, cuando los métodos propios de las clases lo llaman, rápidamente establecen la bandera en verdadero, luego llaman al método y luego establecen la bandera en falso

Al final un poco mudo. Probablemente sea mejor por ahora simplemente colocar la clase privada en la clase misma y cortar la interfaz por completo.

Tyrael Arcángel
fuente