Pergunta

O tópico diz mais sobre isso - qual é a razão do fato de métodos estáticos não poderem ser declarados em uma interface?

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

O código acima me dá o seguinte erro (no Eclipse, pelo menos):"Modificador ilegal para o método de interface ITest.test();apenas público e abstrato são permitidos".

Foi útil?

Solução

Existem alguns problemas em jogo aqui.A primeira é a questão de declarar um método estático sem defini-lo.Esta é a diferença entre

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

e

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

A primeira é impossível pelas razões que Espo menciona:você não sabe qual classe de implementação é a definição correta.

Java poderia permita o último;e de fato, a partir do Java 8, isso acontece!

Outras dicas

A razão pela qual você não pode ter um método estático em uma interface está na maneira como o Java resolve referências estáticas.Java não se preocupará em procurar uma instância de uma classe ao tentar executar um método estático.Isso ocorre porque os métodos estáticos não dependem da instância e, portanto, podem ser executados diretamente do arquivo de classe.Dado que todos os métodos em uma interface são abstratos, a VM teria que procurar uma implementação específica da interface para encontrar o código por trás do método estático para que ele pudesse ser executado.Isso contradiz o modo como a resolução do método estático funciona e introduziria uma inconsistência na linguagem.

Responderei sua pergunta com um exemplo.Suponha que tenhamos uma classe Math com um método estático add.Você chamaria esse método assim:

Math.add(2, 3);

Se Math fosse uma interface em vez de uma classe, não poderia ter nenhuma função definida.Como tal, dizer algo como Math.add(2, 3) não faz sentido.

A razão está no princípio do design, que java não permite herança múltipla.O problema com herança múltipla pode ser ilustrado pelo seguinte exemplo:

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

Agora, o que acontece se você chamar C.x()?Será A.x() ou B.x() executado?Toda linguagem com herança múltipla tem que resolver esse problema.

As interfaces permitem em Java algum tipo de herança múltipla restrita.Para evitar o problema acima, eles não podem ter métodos.Se observarmos o mesmo problema com interfaces e métodos estáticos:

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

O mesmo problema aqui, o que acontece se você ligar para C.x()?

Métodos estáticos não são métodos de instância.Não há contexto de instância, portanto, implementá-lo a partir da interface faz pouco sentido.

Agora Java8 nos permite definir até métodos estáticos na interface.

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
   }
}

Observação:Os métodos na interface ainda são públicos abstratos por padrão se não usarmos explicitamente as palavras-chave default/static para torná-los métodos padrão e métodos estáticos respectivamente.

Há uma resposta muito boa e concisa para sua pergunta aqui.(Pareceu-me uma maneira tão simples de explicar que quero vinculá-la a partir daqui.)

Parece que o método estático na interface pode ser suportado em Java 8, bem, minha solução é apenas defini-los na classe interna.

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

A mesma técnica também pode ser usada em anotações:

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

A classe interna deve sempre ser acessada na forma de Interface.fn... em vez de Class.fn..., então, você pode se livrar do problema ambíguo.

Uma interface é usada para polimorfismo, que se aplica a objetos, não a tipos.Portanto (como já foi observado) não faz sentido ter um membro de interface estático.

Java 8 mudou o mundo, você pode ter métodos estáticos na interface, mas isso força você a fornecer implementação para isso.

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

}

Combinação ilegal de modificadores:estático e abstrato

Se um membro de uma classe for declarado como estático, ele poderá ser usado com seu nome de classe que está confinado a essa classe, sem criar um objeto.

Se um membro de uma classe for declarado como abstrato, você precisará declarar a classe como abstrata e fornecer a implementação do membro abstrato em sua classe herdada (Subclasse).

Você precisa fornecer uma implementação para o membro abstrato de uma classe na subclasse onde você irá alterar o comportamento do método estático, também declarado como abstrato que está confinado à classe base, o que não é correto

Como os métodos estáticos não podem ser herdados.Então não adianta colocá-lo na interface.Interface é basicamente um contrato que todos os seus assinantes devem seguir.Colocar um método estático na interface forçará os assinantes a implementá-lo.o que agora se torna contraditório ao fato de que métodos estáticos não podem ser herdados.

Com Java 8, as interfaces agora podem ter métodos estáticos.

Por exemplo, Comparator possui um método estático naturalOrder().

A exigência de que as interfaces não possam ter implementações também foi flexibilizada.As interfaces agora podem declarar implementações de métodos "padrão", que são como implementações normais com uma exceção:se você herdar uma implementação padrão de uma interface e uma implementação normal de uma superclasse, a implementação da superclasse sempre terá prioridade.

Talvez um exemplo de código ajude, vou usar C#, mas você poderá acompanhar.

Vamos fingir que temos uma interface chamada IPayable

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

Agora, temos duas classes concretas que implementam esta interface:

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

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

Agora, vamos fingir que temos uma coleção de contas diversas, para isso usaremos uma lista genérica do tipo IPayable

List<IPayable> accountsToPay = new List<IPayable>();
accountsToPay.add(new CustomerAccount());
accountsToPay.add(new BusinessAccount());

Agora, queremos pagar $ 50,00 para todas essas contas:

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

Agora você vê como as interfaces são incrivelmente úteis.

Eles são usados ​​apenas em objetos instanciados.Não em classes estáticas.

Se você tivesse tornado o pagamento estático, ao percorrer o IPayable em accountsToPay, não haveria como descobrir se deveria chamar o pagamento em BusinessAcount ou CustomerAccount.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top