¿Por qué no puedo definir un método estático en una interfaz Java?

Aquí está el ejemplo:

public interface IXMLizable { static T newInstanceFromXML(Element e); Element toXMLElement(); } 

Por supuesto, esto no funcionará. ¿Pero por qué no?

Uno de los posibles problemas sería lo que sucede cuando llamas:

 IXMLizable.newInstanceFromXML(e); 

En este caso, creo que debería simplemente 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 todas estarían bien al llamar al método estático. Entonces, ¿por qué no es esto posible?

EDITAR: Creo que estoy buscando una respuesta más profunda que “porque así es Java”.

¿Existe alguna razón tecnológica particular por la que los métodos estáticos no puedan sobrescribirse? Es decir, ¿por qué los diseñadores de Java decidieron convertir los métodos de instancia en métodos anulables pero no estáticos?

EDITAR: El problema con mi diseño es que estoy tratando de usar interfaces para aplicar una convención de encoding.

Es decir, el objective de la interfaz es doble:

  1. Quiero que la interfaz IXMLizable me permita convertir clases que lo implementen en elementos XML (usando polymorphism, funciona bien).

  2. Si alguien quiere crear una nueva instancia de una clase que implemente la interfaz IXMLizable, sabrá siempre que habrá un nuevo constructor estático de InstanceFromXML (Element e).

¿Hay alguna otra forma de asegurar esto, que no sea simplemente poner un comentario en la interfaz?

EDITAR: a partir de Java 8, los métodos estáticos ahora están permitidos en las interfaces.

Java 8 permite métodos de interfaz estáticos

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.

En realidad, hay dos preguntas aquí:

  1. ¿Por qué, en los viejos tiempos, las interfaces no podían contener métodos estáticos?
  2. ¿Por qué no se pueden anular los métodos estáticos?

Métodos estáticos en las interfaces

No había una fuerte razón técnica por la que las interfaces no pudieran tener 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 abandonó debido a complicaciones imprevistas.

Finalmente, Java 8 introdujo métodos de interfaz estáticos, así como métodos de instancia anulables con una implementación predeterminada. Sin embargo, todavía no pueden tener campos de instancia. Estas características son parte del soporte de expresión lambda, y puede leer más sobre ellas en la Parte H de JSR 335.

Reemplazando los 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 comstackción. El despacho dynamic tiene sentido, por ejemplo, en los métodos, donde el comstackdor 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 comstackción, el despacho dynamic no es necesario.

Es necesario conocer un poco sobre cómo funcionan los métodos de instancia para comprender qué 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 (nombres y tipos de parámetros) a un fragmento real de código 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 padre de la clase y la búsqueda se repite allí. Esto continúa hasta encontrar el método, o no hay más clases principales, lo que da como resultado un NoSuchMethodError .

Si una superclase y una subclase tienen una entrada en sus tablas para la misma firma de método, primero se encuentra la versión de la subclase y nunca se utiliza la versión de la superclase; esto es una “anulación”.

Ahora, supongamos que omitimos la instancia del objeto y comenzamos con una subclase. La resolución podría proceder como se indica arriba, dándote una especie de método estático “invalidable”. Sin embargo, la resolución puede ocurrir en tiempo de comstackción, ya que el comstackdor 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 uno siempre 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 quieres ordenar efectivamente un método similar al de un constructor para cada implementación de IXMLizable . Olvídate de intentar imponer esto con una interfaz por un minuto, y finge que tienes algunas clases que cumplen con este requisito. Cómo lo usarías?

 class Foo implements IXMLizable { public static Foo newInstanceFromXML(Element e) { ... } } Foo obj = Foo.newInstanceFromXML(e); 

Ya que tiene que nombrar explícitamente al tipo concreto Foo cuando “construye” el nuevo objeto, el comstackdor puede verificar que efectivamente tiene el método de fábrica necesario. Y si no lo hace, ¿y qué? Si puedo implementar un IXMLizable que carece del “constructor”, y creo una instancia y la paso a su código, es un IXMLizable con toda la interfaz necesaria.

La construcción es parte de la implementación, no de 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 saber el tipo concreto de todos modos, y la interfaz puede ignorarse.

Esto ya fue preguntado y respondido, aquí

Para duplicar mi respuesta:

Nunca hay un punto para declarar un método estático en una interfaz. No pueden ser ejecutados por 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 hacer:

 MyInterface var = new MyImplementingClass(); var.staticMethod(); 

las reglas para static dicen que el método definido en el tipo de var declarado debe ser ejecutado. Como esta es una interfaz, esto es imposible.

La razón por la que no puede ejecutar “result = MyInterface.staticMethod ()” es que debería 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 de esa manera”, en realidad, la decisión es una consecuencia lógica de otras decisiones de diseño, también por una muy buena razón.

Normalmente esto se hace usando un patrón de fábrica

 public interface IXMLizableFactory { public T newInstanceFromXML(Element e); } public interface IXMLizable { public Element toXMLElement(); } 

Con la llegada de Java 8 , ahora es posible escribir métodos predeterminados y estáticos en la interfaz. docs.oracle/staticMethod

Por ejemplo:

 public interface Arithmetic { public int add(int a, int b); public static int multiply(int a, int b) { return a * b; } } 
 public class ArithmaticImplementation implements Arithmetic { @Override public int add(int a, int b) { return a + b; } public static void main(String[] args) { int result = Arithmetic.multiply(2, 3); System.out.println(result); } } 

Resultado : 6

SUGERENCIA: Llamar a un método de interfaz estático 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.

Debido a que 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.

¿Por qué no puedo definir un método estático en una interfaz Java?

De hecho, puedes hacerlo en Java 8.

Según el documento de Java:

Un método estático es un método que está asociado con la clase en la que está definido en lugar de con cualquier objeto. Cada instancia de la clase comparte sus métodos estáticos

En Java 8, una interfaz puede tener métodos predeterminados y métodos estáticos . Esto nos facilita la organización de métodos de ayuda 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:

 list.sort(ordering); 

en lugar de

 Collections.sort(list, ordering); 

Ejemplo de método estático (del propio doc ):

 public interface TimeClient { // ... static public ZoneId getZoneId (String zoneString) { try { return ZoneId.of(zoneString); } catch (DateTimeException e) { System.err.println("Invalid time zone: " + zoneString + "; using default time zone instead."); return ZoneId.systemDefault(); } } default public ZonedDateTime getZonedDateTime(String zoneString) { return ZonedDateTime.of(getLocalDateTime(), getZoneId(zoneString)); } } 

En primer lugar, todas las decisiones sobre el 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 de lenguaje o la escritura de comstackdor / intérprete que diga que un método estático no puede ser parte de una interfaz. Creé un par de idiomas y comstackdores escritos para ellos; todo está sentado y definiendo 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 comstackdor tiene que diferir la resolución del método para el 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 incluye métodos estáticos. No puedo hablar por ninguno de ustedes, pero utilizo métodos estáticos de forma regular.

La respuesta correcta más probable es que no se percibió la necesidad, en el momento en que se definió el idioma, 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 cierto interés. El hecho de que se haya examinado para Java 7 indica que se ha elevado a un nivel de interés que podría dar lugar a un cambio de idioma. Yo, por mi parte, me alegrará cuando ya no tenga que crear una instancia de un objeto solo para que pueda llamar a mi método get no estático para acceder a una variable estática en una instancia de subclase …

Las interfaces están relacionadas con el polymorphism que está intrínsecamente vinculado a las instancias de objeto, no a las clases. Por lo tanto, la estática no tiene sentido en el contexto de una interfaz.

  • “¿Hay alguna razón en particular por la que los métodos estáticos no puedan anularse?”.

Permítame volver a escribir esa pregunta para usted completando las definiciones.

  • “¿Existe algún motivo particular por el que los métodos resueltos en tiempo de comstackción no se puedan resolver en el tiempo de ejecución”.

O, para agregarlo más completamente, si deseo llamar a un método sin una instancia, pero conociendo la clase, ¿cómo puedo resolverla en función de la instancia que no tengo?

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 colocar clases que contengan métodos estáticos dentro de las interfaces. ¡Podrías probar eso!

 public interface Test { static class Inner { public static Object get() { return 0; } } } 

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: tiene que implementarlo o obtendrá un error de comstackción.

Bueno, sin generics, las interfaces estáticas son inútiles porque todas las llamadas a métodos estáticos se resuelven en tiempo de comstackción. Entonces, no hay un uso real para ellos.

Con los generics, tienen uso, con o sin una implementación predeterminada. Obviamente, debería haber una anulación, y así sucesivamente. Sin embargo, creo que ese uso no fue muy OO (como las otras respuestas apuntan obtusamente) y, por lo tanto, no se consideró que valía la pena el esfuerzo que requerirían implementar de manera útil.

Varias respuestas han discutido los problemas con el concepto de métodos estáticos anulables. Sin embargo, a veces te encuentras con un patrón donde parece que 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 diversas razones, cada clase de objeto de valor tiene que definir algunos métodos estáticos que permitan que el marco encuentre la instancia de comando. Por ejemplo, para crear una Persona que harías:

 cmd = createCmd(Person.getCreateCmdId()); Person p = cmd.execute(); 

y para cargar una Persona por ID que harías

 cmd = createCmd(Person.getGetCmdId()); cmd.set(ID, id); Person p = cmd.execute(); 

Esto es bastante conveniente, sin embargo tiene sus problemas; en particular, la existencia de los métodos estáticos no se puede aplicar en la interfaz. Un método estático sobrecargado en la interfaz sería exactamente lo que necesitaríamos, si 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 forma, los métodos “estáticos” pueden anularse según sea necesario, y usted no satura la interfaz normal (se denomina “Remoto”) con métodos que no se aplican a una instancia de su bean. Simplemente haga que la interfaz normal especifique un método “getHome ()”. Devuelvo una instancia del objeto Home (que podría ser un singleton, supongo) y el que llama puede realizar operaciones que afectan a todos los objetos Person.

 Why can't I define a static method in a Java interface? 

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.

Una interfaz nunca se puede desreferenciar estáticamente, por ejemplo, ISomething.member . Una interfaz siempre se desreferencia a través de una variable que hace referencia 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 solo una función con scope 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, por lo tanto, cada método estático es una función con scope de clase que no toma un parámetro “this”. Por lo tanto, normalmente un método estático se puede llamar estáticamente, pero como se estableció anteriormente, una interfaz no tiene implementación (es abstracta).

Por lo tanto, para obtener la aproximación más cercana a un método estático en una interfaz, es utilizar un método no estático, y luego no acceder a ninguno de los miembros de instancia no estáticos. No habría ningún beneficio de rendimiento posible de otra manera, porque no hay forma de vincular estáticamente (en tiempo de comstackción) un ISomething.member() . El único beneficio que veo de un método estático en una interfaz es que no ingresa (es decir, ignora) un “esto” implícito y, por lo tanto, no permite el acceso a ninguno de los miembros de instancia no estáticos. Esto declararía implícitamente que la función que no accede a “esto” está inmutada y ni siquiera es de solo lectura con respecto a su clase contenedora. Pero una statement de “estática” en una interfaz ISomething también confundiría a las personas que intentaron acceder a ella con ISomething.member() lo que provocaría un error en el comstackdor. Supongo que si el error del comstackdor 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 (al parecer principalmente métodos de fábrica), como lo estamos haciendo aquí (y se ha repetido durante 3 Preguntas y respuestas sobre este sitio), por lo que obviamente es un problema que no es intuitivo para muchas personas. Tuve que pensarlo un tiempo para entenderlo correctamente.

La forma de obtener un campo estático mutable en una interfaz es utilizar métodos get y setter no estáticos en una interfaz, para acceder al campo estático que se encuentra en la subclase. Sidenote, statics aparentemente inmutables se pueden declarar en una interfaz Java con static final .

Las interfaces solo proporcionan una lista de las 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 la herede; de ​​lo contrario, elimine la estática.

¡Espero que ayude!

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 lo desea, puede hacer esto:

 public class A { public static void methodX() { } } public class B extends A { public static void methodX() { } } 

En este caso, lo que tienes son dos clases con 2 métodos estáticos distintos llamados methodX ().

Supongamos que pudieras hacerlo; considera este ejemplo:

 interface Iface { public static void thisIsTheMethod(); } class A implements Iface { public static void thisIsTheMethod(){ system.out.print("I'm class A"); } } class B extends Class A { public static void thisIsTheMethod(){ System.out.print("I'm class B"); } } SomeClass { void doStuff(Iface face) { IFace.thisIsTheMethod(); // now what would/could/should happen here. } } 

Algo que podría implementarse es una interfaz estática (en lugar de un método estático en una interfaz). Todas las clases que implementan una interfaz estática determinada deben implementar los métodos estáticos correspondientes. Puede obtener la interfaz estática SI de cualquier Clazz Class usando

 SI si = clazz.getStatic(SI.class); // null if clazz doesn't implement SI // alternatively if the class is known at compile time SI si = Someclass.static.SI; // either compiler errror or not null 

entonces puedes llamar a si.method(params) . Esto sería útil (para el patrón de diseño de fábrica, por ejemplo) porque puede obtener (o verificar la implementación) de la implementación de métodos estáticos SI a partir de una clase desconocida en tiempo de comstackción. Se necesita un despacho dynamic y puede anular los métodos estáticos (si no es el final) 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.

Aunque me doy cuenta de que Java 8 resuelve este problema, pensé en un escenario en el que estoy trabajando actualmente (bloqueado para usar Java 7) donde sería útil poder especificar métodos estáticos en una interfaz.

Tengo varias definiciones enum donde he definido los campos “id” y “displayName” junto con los métodos de ayuda que evalúan los valores por varias razones. La implementación de una interfaz me permite asegurarme de que los métodos getter estén en su lugar, pero no los métodos static helper. Siendo una enumeración, realmente no hay una forma clara de descargar los métodos de ayuda en una clase abstracta heredada o algo así, por lo que los métodos deben definirse en la propia enumeración. También porque es una enumeración, nunca serás capaz de pasarla realmente como un objeto instanciado y tratarla como el tipo de interfaz, pero es capaz de requerir la existencia de los métodos estáticos de ayuda a través de una interfaz. es compatible con Java 8.

Aquí hay un código que ilustra mi punto.

Definición de la interfaz:

 public interface IGenericEnum > { String getId(); String getDisplayName(); //If I was using Java 8 static helper methods would go here } 

Ejemplo de una definición enum:

 public enum ExecutionModeType implements IGenericEnum { STANDARD ("Standard", "Standard Mode"), DEBUG ("Debug", "Debug Mode"); String id; String displayName; //Getter methods public String getId() { return id; } public String getDisplayName() { return displayName; } //Constructor private ExecutionModeType(String id, String displayName) { this.id = id; this.displayName = displayName; } //Helper methods - not enforced by Interface public static boolean isValidId(String id) { return GenericEnumUtility.isValidId(ExecutionModeType.class, id); } public static String printIdOptions(String delimiter){ return GenericEnumUtility.printIdOptions(ExecutionModeType.class, delimiter); } public static String[] getIdArray(){ return GenericEnumUtility.getIdArray(ExecutionModeType.class); } public static ExecutionModeType getById(String id) throws NoSuchObjectException { return GenericEnumUtility.getById(ExecutionModeType.class, id); } } 

Definición de utilidad de enum genérica:

 public class GenericEnumUtility { public static  & IGenericEnum> boolean isValidId(Class enumType, String id) { for(IGenericEnum enumOption : enumType.getEnumConstants()) { if(enumOption.getId().equals(id)) { return true; } } return false; } public static  & IGenericEnum> String printIdOptions(Class enumType, String delimiter){ String ret = ""; delimiter = delimiter == null ? " " : delimiter; int i = 0; for(IGenericEnum enumOption : enumType.getEnumConstants()) { if(i == 0) { ret = enumOption.getId(); } else { ret += delimiter + enumOption.getId(); } i++; } return ret; } public static  & IGenericEnum> String[] getIdArray(Class enumType){ List idValues = new ArrayList(); for(IGenericEnum enumOption : enumType.getEnumConstants()) { idValues.add(enumOption.getId()); } return idValues.toArray(new String[idValues.size()]); } @SuppressWarnings("unchecked") public static  & IGenericEnum> T getById(Class enumType, String id) throws NoSuchObjectException { id = id == null ? "" : id; for(IGenericEnum enumOption : enumType.getEnumConstants()) { if(id.equals(enumOption.getId())) { return (T)enumOption; } } throw new NoSuchObjectException(String.format("ERROR: \"%s\" is not a valid ID. Valid IDs are: %s.", id, printIdOptions(enumType, " , "))); } } 

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 esos serían los no-estáticos. * Cualquier clase que conoce una interfaz en particular podría invocar sus métodos estáticos. Por lo tanto, un método estático de la clase implementadora se llamará debajo, pero la clase invocadora no sabe cuál. Cómo saberlo? ¡No tiene ninguna instancia para adivinar eso!

Se pensó que las interfaces se usaban cuando se trabaja con objetos. De esta manera, un objeto se crea una instancia de una clase particular, por lo que este último asunto se resuelve. La clase invocadora no necesita saber qué clase particular es porque la instanciación puede ser realizada por una tercera clase. Entonces la clase invocadora solo conoce la interfaz.

Si queremos que esto se extienda a métodos estáticos, deberíamos tener la posibilidad de especificar una clase de implementación antes, luego pasar una referencia a la clase invocadora. 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 incluya los antiguos métodos estáticos, que ahora no son estáticos.

Las metaclases sirven para este propósito. Puede probar la clase Clase de 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 tienes que 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.

Para resolver esto: error: missing method body, o declare abstract static void main (String [] args);

 interface I { int x=20; void getValue(); static void main(String[] args){};//Put curly braces } class InterDemo implements I { public void getValue() { System.out.println(x); } public static void main(String[] args) { InterDemo i=new InterDemo(); i.getValue(); } } 

salida: 20

Ahora podemos usar el método estático en la interfaz

Creo que Java no tiene métodos de interfaz estáticos porque no los necesitas. Puede pensar que sí, pero … ¿Cómo los usaría? Si quieres llamarlos como

 MyImplClass.myMethod() 

entonces no necesita declararlo en la interfaz. Si quieres llamarlos como

 myInstance.myMethod() 

entonces no debería ser estático. Si realmente vas a usar la primera vía, pero solo quieres aplicar cada implementación para tener dicho método estático, entonces es realmente una convención de encoding, no un contrato entre instancias que implementa una interfaz y un código de llamada.

Interfaces allow you to define contract between instance of class that implement the interface and calling code. And java helps you to be sure that this contract is not violated, so you can rely on it and don’t worry what class implements this contract, just “someone who signed a contract” is enough. In case of static interfaces your code

 MyImplClass.myMethod() 

does not rely on the fact that each interface implementation has this method, so you do not need java to help you to be sure with it.

What is the need of static method in interface, static methods are used basically when you don’t have to create an instance of object whole idea of interface is to bring in OOP concepts with introduction of static method you’re diverting from concept.

    Intereting Posts