EDITAR: a partir de Java 8, los métodos estáticos ahora están permitidos en las interfaces.
Aquí está el ejemplo:
public interface IXMLizable<T>
{
static T newInstanceFromXML(Element e);
Element toXMLElement();
}
Por supuesto que esto no funcionará. ¿Pero por qué no?
Uno de los posibles problemas sería qué sucede cuando llama:
IXMLizable.newInstanceFromXML(e);
En este caso, creo que debería llamar a un método vacío (es decir, {}). Todas las subclases se verían obligadas a implementar el método estático, por lo que estarían bien al llamar al método estático. Entonces, ¿por qué no es esto posible?
EDITAR: Supongo que estoy buscando una respuesta que sea más profunda que "porque así es Java".
¿Existe una razón tecnológica particular por la cual los métodos estáticos no se pueden sobrescribir? Es decir, ¿por qué los diseñadores de Java decidieron hacer que los métodos de instancia sean reemplazables pero no métodos estáticos?
EDITAR: El problema con mi diseño es que estoy tratando de usar interfaces para aplicar una convención de codificación.
Es decir, el objetivo de la interfaz es doble:
Quiero que la interfaz IXMLizable me permita convertir clases que lo implementen en elementos XML (usando polimorfismo, funciona bien).
Si alguien quiere crear una nueva instancia de una clase que implemente la interfaz IXMLizable, siempre sabrá que habrá un nuevo constructor estáticoInstanceFromXML (Elemento e).
¿Hay alguna otra manera de garantizar esto, aparte de simplemente hacer un comentario en la interfaz?
fuente
Respuestas:
Java 8 permite métodos de interfaz estática
Con Java 8, las interfaces pueden tener métodos estáticos. También pueden tener métodos de instancia concretos, pero no campos de instancia.
Realmente hay dos preguntas aquí:
Métodos estáticos en interfaces.
No había una razón técnica sólida por la cual las interfaces no pudieran haber tenido métodos estáticos en versiones anteriores. Esto se resume muy bien en el póster de una pregunta duplicada. Los métodos de interfaz estática se consideraron inicialmente como un pequeño cambio de idioma, y luego hubo una propuesta oficial para agregarlos en Java 7, pero luego se descartó debido a complicaciones imprevistas.
Finalmente, Java 8 introdujo métodos de interfaz estática, así como métodos de instancia que se pueden anular con una implementación predeterminada. Sin embargo, todavía no pueden tener campos de instancia. Estas características son parte del soporte de expresiones lambda, y puede leer más sobre ellas en la Parte H de JSR 335.
Anulación de métodos estáticos
La respuesta a la segunda pregunta es un poco más complicada.
Los métodos estáticos se pueden resolver en tiempo de compilación. El despacho dinámico tiene sentido para los métodos de ejemplo, donde el compilador no puede determinar el tipo concreto del objeto y, por lo tanto, no puede resolver el método a invocar. Pero invocar un método estático requiere una clase, y dado que esa clase se conoce estáticamente , en tiempo de compilación, el despacho dinámico es innecesario.
Es necesario un poco de información sobre cómo funcionan los métodos de instancia para comprender lo que está sucediendo aquí. Estoy seguro de que la implementación real es bastante diferente, pero permítanme explicar mi noción de envío de métodos, que modela el comportamiento observado con precisión.
Imagine que cada clase tiene una tabla hash que asigna las firmas de métodos (nombre y tipos de parámetros) a un fragmento de código real para implementar el método. Cuando la máquina virtual intenta invocar un método en una instancia, consulta el objeto para su clase y busca la firma solicitada en la tabla de la clase. Si se encuentra un cuerpo de método, se invoca. De lo contrario, se obtiene la clase principal de la clase y la búsqueda se repite allí. Esto continúa hasta que se encuentra el método, o no hay más clases primarias, lo que resulta en a
NoSuchMethodError
.Si una superclase y una subclase tienen una entrada en sus tablas para la misma firma de método, la versión de la subclase se encuentra primero y la versión de la superclase nunca se usa; esto es una "anulación".
Ahora, supongamos que omitimos la instancia del objeto y simplemente comenzamos con una subclase. La resolución podría proceder como anteriormente, dándole una especie de método estático "reemplazable". Sin embargo, la resolución puede suceder en tiempo de compilación, ya que el compilador está comenzando desde una clase conocida, en lugar de esperar hasta el tiempo de ejecución para consultar un objeto de un tipo no especificado para su clase. No tiene sentido "anular" un método estático, ya que siempre se puede especificar la clase que contiene la versión deseada.
Constructor "interfaces"
Aquí hay un poco más de material para abordar la edición reciente de la pregunta.
Parece que desea exigir efectivamente un método similar al constructor para cada implementación de
IXMLizable
. Olvídate de intentar hacer cumplir esto con una interfaz durante un minuto y finge que tienes algunas clases que cumplen con este requisito. Cómo lo usarías?Como debe nombrar explícitamente el tipo concreto
Foo
cuando "construye" el nuevo objeto, el compilador puede verificar que sí tiene el método de fábrica necesario. Y si no es así, ¿y qué? Si puedo implementar unaIXMLizable
que carece del "constructor", y creo una instancia y la paso a su código, es unaIXMLizable
con toda la interfaz necesaria.La construcción es parte de la implementación, no la interfaz. Cualquier código que funcione correctamente con la interfaz no se preocupa por el constructor. Cualquier código que se preocupe por el constructor necesita conocer el tipo concreto de todos modos, y la interfaz puede ignorarse.
fuente
RESET()
en una clase determinada? Tu escribiriasSomeClass.RESET()
. Por lo tanto, no necesita una interfaz para describir esa API; Es estático. Las interfaces se usan cuando no se conoce el tipo concreto en tiempo de compilación. Ese nunca es el caso con un método estático.T
sin saberloT
estáticamente, porque prometo en una interfaz que existirá cierto constructor (o método estático) en tiempo de ejecución. El hecho de que la generación sea imposible de especificar en Java no significa que no sea algo significativo.Esto ya fue preguntado y respondido, aquí
Para duplicar mi respuesta:
Nunca tiene sentido declarar un método estático en una interfaz. No pueden ejecutarse mediante la llamada normal MyInterface.staticMethod (). Si los llama especificando la clase de implementación MyImplementor.staticMethod (), entonces debe conocer la clase real, por lo que es irrelevante si la interfaz la contiene o no.
Más importante aún, los métodos estáticos nunca se anulan, y si intenta hacerlo:
Las reglas para static dicen que el método definido en el tipo de var declarado debe ejecutarse. Como se trata de una interfaz, esto es imposible.
La razón por la que no puede ejecutar "result = MyInterface.staticMethod ()" es que tendría que ejecutar la versión del método definido en MyInterface. Pero no puede haber una versión definida en MyInterface, porque es una interfaz. No tiene código por definición.
Si bien puede decir que esto equivale a "porque Java lo hace así", en realidad la decisión es una consecuencia lógica de otras decisiones de diseño, también tomadas por muy buenas razones.
fuente
static
es un término malo en los idiomas de todos modos, y se ha extendido demasiado como está. Por lo tanto, tenerlo solo ya es incompleto. Vea mi ejemplo anterior stackoverflow.com/questions/512877/… {shrug}.Normalmente esto se hace usando un patrón Factory
fuente
Con la llegada de Java 8 ahora es posible escribir métodos predeterminados y estáticos en la interfaz. docs.oracle/staticMethod
Por ejemplo:
Resultado : 6
CONSEJO: Llamar a un método de interfaz estática no requiere ser implementado por ninguna clase. Seguramente, esto sucede porque las mismas reglas para los métodos estáticos en las superclases se aplican a los métodos estáticos en las interfaces.
fuente
Porque los métodos estáticos no pueden anularse en subclases y, por lo tanto, no pueden ser abstractos. Y todos los métodos en una interfaz son, de facto , abstractos.
fuente
En realidad puedes en Java 8.
Según el documento de Java :
En Java 8, una interfaz puede tener métodos predeterminados y métodos estáticos . Esto nos facilita la organización de métodos auxiliares en nuestras bibliotecas. Podemos mantener métodos estáticos específicos para una interfaz en la misma interfaz en lugar de en una clase separada.
Ejemplo de método predeterminado:
en vez de
Ejemplo de método estático (del propio documento ):
fuente
Las interfaces están relacionadas con el polimorfismo que está inherentemente vinculado a instancias de objetos, no a clases. Por lo tanto, la estática no tiene sentido en el contexto de una interfaz.
fuente
Primero, todas las decisiones de lenguaje son decisiones tomadas por los creadores del lenguaje. No hay nada en el mundo de la ingeniería de software o la definición del lenguaje o la escritura del compilador / intérprete que diga que un método estático no puede ser parte de una interfaz. Creé un par de idiomas y escribí compiladores para ellos; todo es solo sentarse y definir una semántica significativa. Yo diría que la semántica de un método estático en una interfaz es notablemente clara, incluso si el compilador tiene que diferir la resolución del método al tiempo de ejecución.
En segundo lugar, que usemos métodos estáticos significa que hay una razón válida para tener un patrón de interfaz que incluya métodos estáticos: no puedo hablar por ninguno de ustedes, pero uso métodos estáticos de manera regular.
La respuesta correcta más probable es que no se percibía la necesidad, en el momento en que se definió el lenguaje, de métodos estáticos en las interfaces. Java ha crecido mucho a lo largo de los años y este es un elemento que aparentemente ha ganado algo de interés. El hecho de que se haya analizado para Java 7 indica que ha aumentado a un nivel de interés que podría provocar un cambio de idioma. Yo, por mi parte, estaré feliz cuando ya no tenga que instanciar un objeto solo para poder llamar a mi método getter no estático para acceder a una variable estática en una instancia de subclase ...
fuente
Los métodos estáticos no son virtuales como los métodos de instancia, así que supongo que los diseñadores de Java decidieron que no los querían en las interfaces.
Pero puede poner clases que contengan métodos estáticos dentro de las interfaces. ¡Podrías probar eso!
fuente
Permítanme reformular esa pregunta para ustedes completando las definiciones.
O, para decirlo más completamente, si quiero llamar a un método sin una instancia, pero conociendo la clase, ¿cómo puedo resolverlo en función de la instancia que no tengo?
fuente
Varias respuestas han discutido los problemas con el concepto de métodos estáticos reemplazables. Sin embargo, a veces te encuentras con un patrón en el que parece que eso es justo lo que quieres usar.
Por ejemplo, trabajo con una capa relacional de objetos que tiene objetos de valor, pero también tiene comandos para manipular los objetos de valor. Por varias razones, cada clase de objeto de valor tiene que definir algunos métodos estáticos que permiten que el marco encuentre la instancia de comando. Por ejemplo, para crear una Persona que haría:
y para cargar una Persona por ID que harías
Esto es bastante conveniente, sin embargo tiene sus problemas; notablemente la existencia de los métodos estáticos no se puede imponer en la interfaz. Un método estático reemplazable en la interfaz sería exactamente lo que necesitaríamos, si tan solo pudiera funcionar de alguna manera.
Los EJB resuelven este problema teniendo una interfaz de inicio; cada objeto sabe cómo encontrar su Hogar y el Hogar contiene los métodos "estáticos". De esta manera, los métodos "estáticos" pueden anularse según sea necesario, y no abarrotan la interfaz normal (se llama "Remota") con métodos que no se aplican a una instancia de su bean. Simplemente haga que la interfaz normal especifique un método "getHome ()". Devuelve una instancia del objeto Home (que podría ser un singleton, supongo) y la persona que llama puede realizar operaciones que afectan a todos los objetos Person.
fuente
Comentando
EDIT: As of Java 8, static methods are now allowed in interfaces.
Es correcto, los métodos estáticos ya que Java 8 están permitidos en las interfaces, pero su ejemplo aún no funcionará. No puede simplemente definir un método estático: debe implementarlo o obtendrá un error de compilación.
fuente
Bueno, sin genéricos, las interfaces estáticas son inútiles porque todas las llamadas a métodos estáticos se resuelven en tiempo de compilación. Entonces, no hay un uso real para ellos.
Con los genéricos, tienen uso, con o sin una implementación predeterminada. Obviamente, tendría que haber una anulación, etc. Sin embargo, supongo que dicho uso no fue muy OO (como las otras respuestas señalan obtusamente) y, por lo tanto, no se consideró que valiera la pena el esfuerzo que requerirían implementar de manera útil.
fuente
Todos los métodos en una interfaz son explícitamente abstractos y, por lo tanto, no puede definirlos como estáticos porque los métodos estáticos no pueden ser abstractos.
fuente
Una interfaz nunca puede ser desreferenciada estáticamente, por ejemplo
ISomething.member
. Una interfaz siempre se desreferencia a través de una variable que se refiere a una instancia de una subclase de la interfaz. Por lo tanto, una referencia de interfaz nunca puede saber a qué subclase se refiere sin una instancia de su subclase.Por lo tanto, la aproximación más cercana a un método estático en una interfaz sería un método no estático que ignora "esto", es decir, no accede a ningún miembro no estático de la instancia. En la abstracción de bajo nivel, cada método no estático (después de la búsqueda en cualquier vtable) es realmente una función con alcance de clase que toma "esto" como un parámetro formal implícito. Vea el objeto singleton de Scala y la interoperabilidad con Java como evidencia de ese concepto. Y así, cada método estático es una función con alcance de clase que no toma un parámetro "este". Por lo tanto, normalmente un método estático puede llamarse estáticamente, pero como se indicó anteriormente, una interfaz no tiene implementación (es abstracta).
Por lo tanto, obtener la aproximación más cercana a un método estático en una interfaz es utilizar un método no estático, luego no acceder a ninguno de los miembros de la instancia no estática. No habría beneficio de rendimiento posible de otra manera, porque no hay forma de vincular estáticamente (en tiempo de compilación) a
ISomething.member()
. El único beneficio que veo de un método estático en una interfaz es que no ingresaría (es decir, ignoraría) un "esto" implícito y, por lo tanto, no permitiría el acceso a ninguno de los miembros de la instancia no estática. Esto declararía implícitamente que la función que no accede a "esto", es inmutada y ni siquiera es de solo lectura con respecto a su clase que contiene. Pero una declaración de "estática" en una interfazISomething
también confundiría a las personas que intentaron acceder a ella conISomething.member()
lo que causaría un error del compilador. Supongo que si el error del compilador fue suficientemente explicativo, sería mejor que tratar de educar a las personas sobre el uso de un método no estático para lograr lo que quieren (aparentemente, principalmente métodos de fábrica), como lo estamos haciendo aquí (y se ha repetido durante 3 Preguntas y respuestas en este sitio), por lo que obviamente es un problema que no es intuitivo para muchas personas. Tuve que pensarlo por un tiempo para entenderlo correctamente.La forma de obtener un campo estático mutable en una interfaz es usar métodos getter y setter no estáticos en una interfaz, para acceder a ese campo estático que en la subclase. Nota aparte, las estadísticas aparentemente inmutables se pueden declarar en una interfaz Java con
static final
.fuente
Las interfaces solo proporcionan una lista de cosas que proporcionará una clase, no una implementación real de esas cosas, que es lo que es su elemento estático.
Si desea estática, use una clase abstracta y heredela; de lo contrario, elimine la estática.
¡Espero que ayude!
fuente
No puede definir métodos estáticos en una interfaz porque los métodos estáticos pertenecen a una clase, no a una instancia de clase, y las interfaces no son clases. Leer más aquí.
Sin embargo, si quieres puedes hacer esto:
En este caso, lo que tiene son dos clases con 2 métodos estáticos distintos llamados methodX ().
fuente
Supongamos que puedes hacerlo; considera este ejemplo:
fuente
A.thisIsTheMethod()
, imprimiría "Soy de clase B".B.thisIsTheMethod()
, se imprimirá "Soy de clase B".Algo que podría implementarse es la interfaz estática (en lugar del método estático en una interfaz). Todas las clases que implementan una interfaz estática dada deben implementar los métodos estáticos correspondientes. Puede obtener una interfaz SI estática desde cualquier clase clazz usando
entonces puedes llamar
si.method(params)
. ¡Esto sería útil (por ejemplo, para el patrón de diseño de fábrica) porque puede obtener (o verificar la implementación de) la implementación de métodos estáticos SI desde una clase desconocida en tiempo de compilación! Es necesario un despacho dinámico y puede anular los métodos estáticos (si no son finales) de una clase extendiéndolo (cuando se llama a través de la interfaz estática). Obviamente, estos métodos solo pueden acceder a variables estáticas de su clase.fuente
Si bien me doy cuenta de que Java 8 resuelve este problema, pensé en intervenir en un escenario en el que estoy trabajando actualmente (bloqueado con el uso de Java 7) donde sería útil poder especificar métodos estáticos en una interfaz.
Tengo varias definiciones de enumeración donde he definido los campos "id" y "displayName" junto con métodos auxiliares que evalúan los valores por varias razones. La implementación de una interfaz me permite garantizar que los métodos getter estén en su lugar, pero no los métodos auxiliares estáticos. Al ser una enumeración, realmente no hay una manera limpia de descargar los métodos auxiliares en una clase abstracta heredada o algo similar, por lo que los métodos deben definirse en la enumeración misma. Además, debido a que es una enumeración, nunca podría pasarlo realmente como un objeto instanciado y tratarlo como el tipo de interfaz, pero poder exigir la existencia de los métodos auxiliares estáticos a través de una interfaz es lo que me gusta de está soportado en Java 8.
Aquí hay un código que ilustra mi punto.
Definición de interfaz:
Ejemplo de una definición de enumeración:
Definición de utilidad genérica enum:
fuente
Supongamos que se permitieran métodos estáticos en las interfaces: * Forzarían a todas las clases implementadoras a declarar ese método. * Las interfaces generalmente se usarían a través de objetos, por lo que los únicos métodos efectivos en ellas serían los no estáticos. * Cualquier clase que conozca una interfaz particular podría invocar sus métodos estáticos. Por lo tanto, el método estático de una clase implementadora se llamaría debajo, pero la clase invocador no sabe cuál. ¿Cómo saberlo? ¡No tiene instanciación adivinar eso!
Se pensaba que las interfaces se usaban al trabajar con objetos. De esta manera, un objeto se instancia de una clase particular, por lo que este último asunto se resuelve. La clase que invoca no necesita saber qué clase en particular es porque la instanciación puede ser realizada por una tercera clase. Entonces la clase que invoca solo conoce la interfaz.
Si queremos que esto se extienda a los métodos estáticos, deberíamos tener la posibilidad de especificar una clase de implementación antes, y luego pasar una referencia a la clase que invoca. Esto podría usar la clase a través de los métodos estáticos en la interfaz. Pero, ¿cuál es la diferencia entre esta referencia y un objeto? Solo necesitamos un objeto que represente lo que era la clase. Ahora, el objeto representa la clase anterior y podría implementar una nueva interfaz que incluye los métodos estáticos antiguos, que ahora no son estáticos.
Las metaclases sirven para este propósito. Puedes probar la clase Class of Java. Pero el problema es que Java no es lo suficientemente flexible para esto. No puede declarar un método en el objeto de clase de una interfaz.
Este es un problema meta: cuando necesitas hacer el culo
..blah blah
de todos modos, tiene una solución fácil: hacer que el método no sea estático con la misma lógica. Pero luego tendría que crear primero un objeto para llamar al método.
fuente
Para resolver esto: error: falta el cuerpo del método o declara el vacío estático abstracto main (String [] args);
salida: 20
Ahora podemos usar el método estático en la interfaz
fuente
Creo que Java no tiene métodos de interfaz estática porque no los necesita. Puede pensar que lo hace, pero ... ¿Cómo los usaría? Si quieres llamarlos como
entonces no necesita declararlo en la interfaz. Si quieres llamarlos como
entonces no debería ser estático. Si realmente va a usar la primera manera, pero solo quiere imponer que cada implementación tenga un método estático, entonces es realmente una convención de codificación, no un contrato entre instancias que implementa una interfaz y un código de llamada.
Las interfaces le permiten definir el contrato entre la instancia de clase que implementa la interfaz y el código de llamada. Y Java le ayuda a asegurarse de que este contrato no se viole, por lo que puede confiar en él y no preocuparse de qué clase implementa este contrato, solo "alguien que firmó un contrato" es suficiente. En caso de interfaces estáticas su código
no se basa en el hecho de que cada implementación de interfaz tiene este método, por lo que no necesita Java para ayudarlo a estar seguro.
fuente
¿Cuál es la necesidad de un método estático en la interfaz? Los métodos estáticos se utilizan básicamente cuando no es necesario crear una instancia de objeto. La idea general de la interfaz es incorporar los conceptos OOP con la introducción del método estático que está desviando del concepto.
fuente