¿Por qué no puedo declarar métodos estáticos en una interfaz?

El tema dice más: ¿cuál es la razón por la cual los métodos estáticos no se pueden declarar en una interfaz?

public interface ITest { public static String test(); } 

El código anterior me da el siguiente error (en Eclipse, al menos): “Se permite el modificador ilegal para el método de interfaz ITest.test (); solo public y abstract”.

Hay algunos problemas en juego aquí. El primero es el problema de declarar un método estático sin definirlo. Esta es la diferencia entre

 public interface Foo { public static int bar(); } 

y

 public interface Foo { public static int bar() { ... } } 

El primero es imposible por las razones que menciona Espo : no se sabe qué clase de implementación es la correcta.

Java podría permitir lo último; y de hecho, comenzando en Java 8, ¡sí!

La razón por la que no puede tener un método estático en una interfaz reside en la forma en que Java resuelve las referencias estáticas. Java no se molestará en buscar una instancia de una clase cuando intente ejecutar un método estático. Esto se debe a que los métodos estáticos no dependen de la instancia y, por lo tanto, se pueden ejecutar directamente desde el archivo de clase. Dado que todos los métodos en una interfaz son abstractos, la VM debería buscar una implementación particular de la interfaz para encontrar el código detrás del método estático para que pueda ser ejecutado. Esto contradice la forma en que funciona la resolución de métodos estáticos e introduciría una incoherencia en el lenguaje.

Responderé a tu pregunta con un ejemplo. Supongamos que tenemos una clase de Matemáticas con un método estático add. Llamarías a este método así:

 Math.add(2, 3); 

Si Math fuera una interfaz en lugar de una clase, no podría tener ninguna función definida. Como tal, decir algo como Math.add (2, 3) no tiene sentido.

La razón radica en el principio de diseño, que java no permite herencia múltiple. El problema con la herencia múltiple se puede ilustrar con el siguiente ejemplo:

 public class A { public method x() {...} } public class B { public method x() {...} } public class C extends A, B { ... } 

Ahora, ¿qué pasa si llamas a Cx ()? ¿Se ejecutará Ax () o Bx ()? Cada idioma con herencia múltiple tiene que resolver este problema.

Las interfaces permiten en Java algún tipo de herencia múltiple restringida. Para evitar el problema anterior, no se les permite tener métodos. Si observamos el mismo problema con las interfaces y los métodos estáticos:

 public interface A { public static method x() {...} } public interface B { public static method x() {...} } public class C implements A, B { ... } 

El mismo problema aquí, ¿qué pasa si llamas a Cx ()?

Los métodos estáticos no son métodos de instancia. No hay contexto de instancia, por lo tanto, implementarlo desde la interfaz tiene poco sentido.

Ahora Java8 nos permite definir incluso métodos estáticos en la interfaz.

 interface X { static void foo() { System.out.println("foo"); } } class Y implements X { //... } public class Z { public static void main(String[] args) { X.foo(); // Y.foo(); // won't compile because foo() is a Static Method of X and not Y } } 

Nota: Los métodos en la interfaz siguen siendo públicos por defecto si no usamos explícitamente las palabras clave default / static para convertirlos en métodos Defender y métodos estáticos resp.

Hay una respuesta muy agradable y concisa a su pregunta aquí . (Me pareció una forma tan sencilla de explicarlo que quiero vincularlo desde aquí).

Parece que el método estático en la interfaz podría ser compatible con Java 8 , bueno, mi solución es simplemente definirlos en la clase interna.

 interface Foo { // ... class fn { public static void func1(...) { // ... } } } 

La misma técnica también se puede usar en anotaciones:

 public @interface Foo { String value(); class fn { public static String getValue(Object obj) { Foo foo = obj.getClass().getAnnotation(Foo.class); return foo == null ? null : foo.value(); } } } 

Siempre se debe acceder a la clase interna en forma de Interface.fn... lugar de Class.fn... , entonces, puede deshacerse de un problema ambiguo.

Se usa una interfaz para el polymorphism, que se aplica a los objetos, no a los tipos. Por lo tanto (como ya se señaló) no tiene sentido tener un miembro de interfaz estático.

Java 8 Si hubiera cambiado el mundo, puede tener métodos estáticos en la interfaz, pero le obliga a implementarlo.

 public interface StaticMethodInterface { public static int testStaticMethod() { return 0; } /** * Illegal combination of modifiers for the interface method * testStaticMethod; only one of abstract, default, or static permitted * * @param i * @return */ // public static abstract int testStaticMethod(float i); default int testNonStaticMethod() { return 1; } /** * Without implementation. * * @param i * @return */ int testNonStaticMethod(float i); 

}

Combinación ilegal de modificadores: estáticos y abstractos

Si un miembro de una clase se declara como estático, se puede usar con su nombre de clase que se limita a esa clase, sin crear un objeto.

Si un miembro de una clase se declara como abstracto, debe declarar la clase como abstracta y debe proporcionar la implementación del miembro abstracto en su clase heredada (Subclase).

Debe proporcionar una implementación al miembro abstracto de una clase en la subclase donde va a cambiar el comportamiento del método estático, también declarado como abstracto, que está confinado a la clase base, lo cual no es correcto.

Dado que los métodos estáticos no pueden ser heredados. Así que no sirve de nada colocarlo en la interfaz. La interfaz es básicamente un contrato que todos sus suscriptores deben seguir. Colocar un método estático en la interfaz obligará a los suscriptores a implementarlo. que ahora se vuelve contradictorio al hecho de que los métodos estáticos no pueden ser heredados.

Tal vez un ejemplo de código ayude, voy a usar C #, pero deberías poder seguirlo.

Supongamos que tenemos una interfaz llamada IPayable

 public interface IPayable { public Pay(double amount); } 

Ahora, tenemos dos clases concretas que implementan esta interfaz:

 public class BusinessAccount : IPayable { public void Pay(double amount) { //Logic } } public class CustomerAccount : IPayable { public void Pay(double amount) { //Logic } } 

Ahora, imaginemos que tenemos una colección de varias cuentas, para hacer esto utilizaremos una lista genérica del tipo de IPayable

 List accountsToPay = new List(); accountsToPay.add(new CustomerAccount()); accountsToPay.add(new BusinessAccount()); 

Ahora, queremos pagar $ 50.00 a todas esas cuentas:

 foreach (IPayable account in accountsToPay) { account.Pay(50.00); } 

Entonces ahora ves cómo las interfaces son increíblemente útiles.

Se usan solo en objetos instanciados. No en clases estáticas

Si hubiera hecho el pago estático, al pasar por el IPayable en accountsToPay no habría forma de averiguar si debería llamar a pagar en BusinessAcount o CustomerAccount.