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

150

El tema dice más: ¿cuál es la razón del hecho de que 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): "Modificador ilegal para el método de interfaz ITest.test (); solo se permiten public & abstract".

Henrik Paul
fuente
2
No acepte la respuesta de Espo, ya que es defectuosa. Una interfaz tiene un archivo de clase que podría contener la implementación de un método estático (si el diseñador Java lo permitiera), por lo que no hay ningún problema en resolver la implementación del método estático. Funciona exactamente como con otras clases estáticas.
Mnementh
Estoy de acuerdo con la respuesta dada por "erickson" stackoverflow.com/questions/512877/…
Maverick
9
Estará disponible en Java 8 por cierto.
m0skit0
1
@Vadorequest GIYF pero de todos modos, verifique aquí
m0skit0
2
Enlaces de la documentación oficial: Java SE tutorial y Java Language Specification 9.2
LoganMzz

Respuestas:

85

Hay algunos problemas en juego aquí. El primero es la cuestión 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() {
    ...
  }
}

La primera es imposible por las razones que menciona Espo : no sabes qué clase de implementación es la definición correcta.

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

James A. Rosen
fuente
2
Sí, es idealógico, no técnico. La razón por la que me gustaría es. que uno puede tener un método de "implementación" estático en una interfaz que solo hace referencia a otros métodos de "interfaz" en la interfaz que se pueden reutilizar fácilmente mediante la implementación de clases. Pero uno puede declarar una clase estática en una interfaz, por lo que podría hacer que tales cosas residan allí como MyInterface.Impl.doIt (MyInterface i, Object [] args) {...}
peterk
9
Desde Java 8, puede definir staticmétodos en un interface. Los métodos deben ser public.
Olivier Grégoire
44
@ OlivierGrégoire ... y no se heredan, lo cual es clave.
William F. Jameson
1
Buena respuesta, aunque ROFLMAO xD "aproximadamente equivalente" lo habría dicho más como "algo parecido".
Timo
44

La razón por la que no puede tener un método estático en una interfaz radica 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 tendría que buscar una implementación particular de la interfaz para encontrar el código detrás del método estático para poder ejecutarlo. Esto contradice cómo funciona la resolución del método estático e introduciría una inconsistencia en el lenguaje.

Espo
fuente
3
Esta explicación no explica el problema. Cada interfaz tiene su propio archivo de clase, podría contener el método estático. Por lo tanto, no sería necesario buscar una implementación particular.
Mnementh
No todos los tipos de interfaz en Java están dentro de su propio archivo, ni deberían estar de acuerdo con JLS. Además, JLS no estipula que las clases deben almacenarse siempre dentro de un sistema de archivos, sino todo lo contrario.
Vlad Gudim
44
@Totophil: Las interfaces no deben estar en un solo archivo java, pero tendrá un archivo de clase propio después de la compilación. Eso es lo que escribí.
Mnementh
18

Contestaré tu pregunta con un ejemplo. Supongamos que tenemos una clase de matemáticas con un método estático agregar. 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.

Kyle Cronin
fuente
11

La razón radica en el principio de diseño, que Java no permite la 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 { ... }

¿Qué sucede 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é sucede si llamas a Cx ()?

Mnementh
fuente
¿Alguna razón para el voto negativo? Un comentario explicativo sería bueno.
Mnementh
no soy el votante, pero ¿no es esto válido también para métodos no estáticos?
nawfal
OK, aquí hay dos posibilidades diferentes. Un método podría implementarse o solo declararse. Comprendí que el método estático tiene que ser implementado. En ese sentido, encuentro el problema presentado en mi respuesta. Si no haces eso, te encuentras con el problema descrito por Espo, y eso no lo entiendo porque asumí que se implementaría el método estático. Tampoco puede declarar un método abstracto estático por este motivo, pruébelo, el compilador se quejará.
Mnementh
Ok, olvida la parte de implementación. La pregunta es por qué no podemos declarar. Sí, el compilador se quejará y por qué esa es la pregunta. a lo que no creo que hayas respondido.
nawfal
1
¿Cómo sería la situación allí peor que tener la interfaz Acontener int x(int z);y la interfaz Bcontener string x(int x);? ¿Cuál es el significado de x(3)en la interfaz C?
supercat
7

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.

Ryan Farley
fuente
5

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 abstractos públicos de forma predeterminada si no utilizamos explícitamente las palabras clave default / static para convertirlos en métodos predeterminados y métodos estáticos resp.

Anandaraja_Srinivasan
fuente
4

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

Zarkonnen
fuente
Esta no es una respuesta a la pregunta, en el mejor de los casos debería ser un comentario.
CubeJockey
3

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 utilizar 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, en Interface.fn...lugar de Class.fn..., entonces, puede deshacerse del problema ambiguo.

Xiè Jìléi
fuente
2

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

Rob Cooper
fuente
Sin embargo
Cruncher
1

Java 8 había cambiado el mundo, puedes tener métodos estáticos en la interfaz, pero te obliga a proporcionar una implementación para eso.

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);

}

Kumar Abhishek
fuente
0

Combinación ilegal de modificadores: estática y abstracta.

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.

Sankar
fuente
¿Cómo responde esto a la pregunta? El OP preguntó sobre la interfaz mientras escribías sobre la clase.
Lucky
0

Dado que los métodos estáticos no se pueden heredar. 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 se pueden heredar.

ip_x
fuente
Los métodos estáticos siempre se heredan, pero no se pueden anular.
Akki
0

Con Java 8 , las interfaces ahora pueden tener métodos estáticos.

Por ejemplo, Comparator tiene un método estático naturalOrder ().

El requisito de que las interfaces no pueden tener implementaciones también se ha relajado. Las interfaces ahora pueden declarar implementaciones de métodos "predeterminados", que son como implementaciones normales con una excepción: si hereda tanto una implementación predeterminada de una interfaz como una implementación normal de una superclase, la implementación de la superclase siempre tendrá prioridad.

Ishara
fuente
¡DIOS MIO! Tenemos un programador serio (y yo, comentarista) respondiendo (y yo comentando) una pregunta de 10 años.
Mohamed Anees A
No noté la fecha :)
Ishara
¡Jaja! ¡No hay problema!
Mohamed Anees A
-2

Quizás un ejemplo de código ayudaría, voy a usar C #, pero debería 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, supongamos que tenemos una colección de varias cuentas, para ello utilizaremos una lista genérica del tipo IPayable

List<IPayable> accountsToPay = new List<IPayable>();
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);
}

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

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

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

FlySwat
fuente
El hecho de que los métodos estáticos no tengan sentido en ESTE ejemplo, no significa que no tengan sentido en CUALQUIER ejemplo. En su ejemplo, si la interfaz IPayable tenía un método estático "IncrementPayables" que realizaba un seguimiento de cuántas cuentas por pagar se agregaron, este sería un caso de uso real. Por supuesto, uno siempre podría usar una clase abstracta, pero eso no fue lo que abordó. Su ejemplo en sí mismo no socava los métodos estáticos en las interfaces.
Cruncher