java - polimorfismo - Constructor en una interfaz?
java interface vs abstract class (11)
Aquí hay un ejemplo usando esta Técnica. En este ejemplo específico, el código realiza una llamada a Firebase utilizando un MyCompletionListener
falso que es una interfaz enmascarada como clase abstracta, una interfaz con un constructor
private interface Listener {
void onComplete(databaseError, databaseReference);
}
public abstract class MyCompletionListener implements Listener{
String id;
String name;
public MyCompletionListener(String id, String name) {
this.id = id;
this.name = name;
}
}
private void removeUserPresenceOnCurrentItem() {
mFirebase.removeValue(child("some_key"), new MyCompletionListener(UUID.randomUUID().toString(), "removeUserPresenceOnCurrentItem") {
@Override
public void onComplete(DatabaseError databaseError, DatabaseReference databaseReference) {
}
});
}
}
@Override
public void removeValue(DatabaseReference ref, final MyCompletionListener var1) {
CompletionListener cListener = new CompletionListener() {
@Override
public void onComplete(DatabaseError databaseError, DatabaseReference databaseReference) {
if (var1 != null){
System.out.println("Im back and my id is: " var1.is + " and my name is: " var1.name);
var1.onComplete(databaseError, databaseReference);
}
}
};
ref.removeValue(cListener);
}
Sé que no es posible definir un constructor en una interfaz. Pero me pregunto por qué, porque creo que podría ser muy útil.
Por lo tanto, puede estar seguro de que se definen algunos campos en una clase para cada implementación de esta interfaz.
Por ejemplo, considere la siguiente clase de mensaje:
public class MyMessage {
public MyMessage(String receiver) {
this.receiver = receiver;
}
private String receiver;
public void send() {
//some implementation for sending the mssage to the receiver
}
}
Si defino una interfaz para esta clase para poder tener más clases que implementen la interfaz del mensaje, solo puedo definir el método de envío y no el constructor. Entonces, ¿cómo puedo asegurarme de que cada implementación de esta clase realmente tenga un receptor configurado? Si utilizo un método como setReceiver(String receiver)
no puedo estar seguro de que se llame realmente este método. En el constructor podría asegurarlo.
Esto se debe a que las interfaces no permiten definir el cuerpo del método en él. Pero deberíamos definir el constructor en la misma clase que las interfaces tienen por defecto el modificador abstracto para todos los métodos para definir. Es por eso que no podemos definir constructor en las interfaces.
Generalmente los constructores son para inicializar miembros no estáticos de una clase particular con respecto al objeto.
No hay creación de objetos para la interfaz, ya que solo hay métodos declarados pero no definidos. Por qué no podemos crear un objeto para los métodos declarados La creación de un objeto is no es otra cosa que la asignación de cierta memoria (en la memoria del montón) para miembros no estáticos.
JVM creará memoria para los miembros que están completamente desarrollados y listos para usar. De acuerdo con esos miembros, JVM calcula cuánta memoria se requiere para ellos y crea memoria.
En el caso de los métodos declarados, JVM no puede calcular la cantidad de memoria necesaria para estos métodos declarados, ya que la implementación será en el futuro, lo que no está hecho en este momento. por lo que la creación de objetos no es posible para la interfaz.
conclusión:
sin creación de objetos, no hay posibilidad de inicializar miembros no estáticos a través de un constructor. Es por eso que el constructor no está permitido dentro de una interfaz (ya que no se usa el constructor dentro de una interfaz)
Las dependencias que no están referenciadas en un método de interfaz deben considerarse como detalles de implementación, no como algo que la interfaz impone. Por supuesto, puede haber excepciones, pero por regla general, debe definir su interfaz como cuál se espera que sea el comportamiento. El estado interno de una implementación determinada no debe ser una preocupación de diseño de la interfaz.
Si desea asegurarse de que cada implementación de la interfaz contenga un campo específico, simplemente necesita agregar a su interfaz el getter para ese campo :
interface IMyMessage(){
@NonNull String getReceiver();
}
- no romperá la encapsulación
- hará saber a todos los que usan su interfaz que el objeto
Receiver
se debe pasar a la clase de alguna manera (ya sea por constructor o por instalador)
Solo hay campos estáticos en la interfaz que no necesitan inicializarse durante la creación del objeto en la subclase y el método de la interfaz debe proporcionar la implementación real en la subclase. Por lo tanto, no es necesario el constructor en la interfaz.
Segundo motivo: durante la creación del objeto de la subclase, se llama al constructor padre. Pero si hay más de una interfaz implementada, se producirá un conflicto durante la llamada del constructor de la interfaz en cuanto al constructor de la interfaz que llamará primero
Tomando algunas de las cosas que has descrito:
"Así que puede estar seguro de que algunos campos de una clase se definen para cada implementación de esta interfaz".
"Si a definir una interfaz para esta clase para que pueda tener más clases que implementen la interfaz del mensaje, solo puedo definir el método de envío y no el constructor"
... estos requisitos son exactamente para lo que son las clases abstractas .
Un problema que obtienes al permitir constructores en las interfaces proviene de la posibilidad de implementar varias interfaces al mismo tiempo. Cuando una clase implementa varias interfaces que definen diferentes constructores, la clase tendría que implementar varios constructores, cada uno satisfaciendo solo una interfaz, pero no las otras. Será imposible construir un objeto que llame a cada uno de estos constructores.
O en el código:
interface Named { Named(String name); }
interface HasList { HasList(List list); }
class A implements Named, HasList {
/** implements Named constructor.
* This constructor should not be used from outside,
* because List parameter is missing
*/
public A(String name) {
...
}
/** implements HasList constructor.
* This constructor should not be used from outside,
* because String parameter is missing
*/
public A(List list) {
...
}
/** This is the constructor that we would actually
* need to satisfy both interfaces at the same time
*/
public A(String name, List list) {
this(name);
// the next line is illegal; you can only call one other super constructor
this(list);
}
}
Un trabajo que puede intentar es definir un método getInstance()
en su interfaz para que el implementador sepa qué parámetros deben manejarse. No es tan sólido como una clase abstracta, pero permite una mayor flexibilidad como interfaz.
Sin embargo, esta solución requiere que use getInstance()
para crear una instancia de todos los objetos de esta interfaz.
P.ej
public interface Module {
Module getInstance(Receiver receiver);
}
Una interfaz define un contrato para una API, que es un conjunto de métodos que acuerdan tanto el implementador como el usuario de la API. Una interfaz no tiene una implementación instanciada, por lo tanto no hay constructor.
El caso de uso que describe es similar a una clase abstracta en la que el constructor llama a un método de un método abstracto que se implementa en una clase secundaria.
El problema inherente aquí es que mientras el constructor base se está ejecutando, el objeto hijo no está construido aún, y por lo tanto en un estado impredecible.
Para resumir: ¿está pidiendo problemas cuando llamas a métodos sobrecargados de los constructores padres, para citar a mindprod :
En general, debe evitar llamar a cualquier método no final en un constructor. El problema es que la inicialización de instancias / inicialización de variable en la clase derivada se realiza después del constructor de la clase base.
Vea esta pregunta por el por qué (tomado de los comentarios).
Si realmente necesita hacer algo como esto, es posible que desee una clase base abstracta en lugar de una interfaz.