Sé que no es posible definir un constructor en una interfaz. Pero me pregunto por qué, porque creo que podría ser muy útil.
Entonces puede estar seguro de que algunos campos en una clase están definidos 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 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. Entonces, ¿cómo puedo asegurarme de que cada implementación de esta clase realmente tenga un conjunto de receptores? Si uso un método como setReceiver(String receiver)
No puedo estar seguro de que este método realmente se llame. En el constructor pude asegurarlo.
mate b
Tomando algunas de las cosas que has descrito:
“Entonces puede estar seguro de que algunos campos en una clase están definidos para cada implementación de esta interfaz”.
“Si defino 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 lo que clases abstractas son para.
-
pero tenga en cuenta que el caso de uso que describe @Sebi (llamar a métodos sobrecargados de los constructores principales) es una mala idea, como se explica en mi respuesta.
– rsp
10 mayo 2010 a las 15:57
-
Matt, eso es claramente cierto, pero las clases abstractas sufren la limitación de herencia única, lo que lleva a las personas a buscar otras formas de especificar jerarquías.
– CPerkins
10 de mayo de 2010 a las 16:09
-
Esto es cierto y puede resolver el problema inmediato de Sebi. Pero una razón para usar interfaces en Java es que no puede tener herencia múltiple. En un caso en el que no puedo convertir mi “cosa” en una clase abstracta porque necesito heredar de otra cosa, el problema persiste. No es que pretenda tener una solución.
– Jay
10 mayo 2010 a las 16:10
-
@CPerkins si bien esto es cierto, no estoy sugiriendo que el simple uso de una clase abstracta resuelva el caso de uso de Sebi. En todo caso, lo mejor es declarar un
Message
interfaz que define elsend()
método, y si Sebi desea proporcionar una clase “base” para implementaciones delMessage
interfaz, luego proporcione unaAbstractMessage
también. Las clases abstractas no deberían tomar el lugar de las interfaces, nunca intenté sugerirlo.– mate b
10 mayo 2010 a las 16:17
-
Entendido, Mat. No estaba discutiendo contigo, más bien señalando que no es un completo reemplazo de lo que quiere el op.
– CPerkins
10 mayo 2010 a las 20:04
daniel kullmann
Un problema que surge cuando permite 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 de los cuales satisfaría solo una interfaz, pero no las demás. Será imposible construir un objeto que llame a cada uno de estos constructores.
O en 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);
}
}
-
¿No podría haberlo hecho el lenguaje al permitir cosas como
class A implements Named, HashList { A(){HashList(new list()); Named("name");} }
– Mako
10 de septiembre de 2013 a las 23:19
-
El significado más útil para un “constructor en una interfaz”, si se permite, sería si
new Set<Fnord>()
podría interpretarse como “Dame algo que pueda usar comoSet<Fnord>
“; si el autor deSet<T>
destinadoHashSet<T>
para ser la implementación de acceso para cosas que no tenían una necesidad particular de otra cosa, la interfaz podría definirnew Set<Fnord>()
podría considerarse sinónimo denew HashSet<Fnord>()
. Que una clase implemente múltiples interfaces no supondría ningún problema, ya quenew InterfaceName()
simplemente construiría una clase designado por la interfaz.– Super gato
10/02/2014 a las 23:45
-
Contraargumento: su
A(String,List)
constructor podría ser el constructor designado, yA(String)
yA(List)
podrían ser los secundarios que lo llaman. Su código no es un contraejemplo, solo uno pobre.– Ky.
7 de febrero de 2018 a las 3:02
-
¿Por qué llamarías? todos los constructores en una implementación?! Sí, si implementa más interfaces con ctor, una con una cadena y otra con un int, necesita esos dos ctores, pero se puede usar o . Si eso no es aplicable, la clase simplemente no implementa ambas interfaces. ¿¡Y qué!? (aunque hay otras razones para no tener ctor en interfaces).
– kai
22 de marzo de 2019 a las 12:52
-
@kai No, necesita llamar a ambos constructores de interfaz al construir una instancia. En otras palabras: en mi ejemplo, la instancia tiene tanto un nombre como una lista, por lo que cada instancia debe instanciar tanto el nombre como la lista.
– daniel kullman
08/04/2019 a las 15:59
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 tiene 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 se ejecuta el constructor base, el objeto secundario aún no se construye y, por lo tanto, se encuentra en un estado impredecible.
Para resumir: ¿está buscando problemas cuando llama a métodos sobrecargados de constructores principales, para citar menteprod:
En general, debe evitar llamar a métodos no finales en un constructor. El problema es que se realizan inicializadores de instancia/inicialización de variables en la clase derivada
después el constructor de la clase base.
Una solución alternativa que puede intentar es definir un 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 más flexibilidad al ser una interfaz.
Sin embargo, esta solución alternativa requiere que utilice el getInstance()
para instanciar todos los objetos de esta interfaz.
P.ej
public interface Module {
Module getInstance(Receiver receiver);
}
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 una implementación real en la subclase. Por lo tanto, no es necesario un constructor en la interfaz.
Segunda razón: durante la creación del objeto de la subclase, se llama al constructor principal. Pero si se implementará más de una interfaz, se producirá un conflicto durante la llamada del constructor de interfaz en cuanto a qué constructor de interfaz llamará primero.
Denys Vasylenko
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
Receiver
el objeto debe pasarse a la clase de alguna manera (ya sea por el constructor o por el setter)
Yishai
Las dependencias a las que no se hace referencia en los métodos de una interfaz deben considerarse detalles de implementación, no algo que la interfaz impone. Por supuesto, puede haber excepciones, pero como regla, debe definir su interfaz como se espera que sea el comportamiento. El estado interno de una implementación dada no debería ser una preocupación de diseño de la interfaz.
posible duplicado de ¿Por qué no se nos permite especificar un constructor en una interfaz?
– mate b
10 mayo 2010 a las 15:42
Dices “En el constructor podría asegurar [every implementation of this class really has an receiver set].” Pero no, posiblemente no podría hacer eso. Siempre que fuera posible definir dicho constructor, el parámetro solo sería una fuerte pista para sus implementadores, pero podrían optar por ignorarlo si quisieran.
– Julien Silland
11 de mayo de 2010 a las 3:08
@mattb Umm, ese es un idioma diferente.
– Yesennes
23 de enero de 2016 a las 20:21
Si desea asegurarse de que una clase tenga un determinado constructor
B
para algún propósito funcionalP
considere exigir queP
recibe elB
como un parámetro en alguna parte. De esa manera, dependiendo de cómo lo declares, (Supplier
,BiFunction
…), puede garantizar el comportamiento. Para ver un ejemplo, eche un vistazo a esta solución.– soy franco
19 abr a las 23:23