Por que há métodos estáticos em interfaces, mas campos e classes internas estáticas OK? [Pré-Java 8] [duplicado]

StackOverflow https://stackoverflow.com/questions/129267

  •  02-07-2019
  •  | 
  •  

Pergunta

Esta questão já tem uma resposta aqui:

Houve algumas perguntas aqui sobre por que você não pode definir métodos estáticos dentro de interfaces, mas nenhum deles abordar uma inconsistência básica: por que você pode definir campos estáticos e tipos internas estáticas dentro de uma interface, mas não métodos estáticos ?

estáticos tipos internos, talvez, não são uma comparação justa, uma vez que é apenas açúcar sintático que gera uma nova classe, mas por campos, mas não métodos?

Um argumento contra métodos estáticos dentro de interfaces é que ele quebra a estratégia de resolução tabela virtual utilizado pela JVM, mas que não deve aplicar-se igualmente aos campos estáticos, ou seja, o compilador pode apenas em linha-lo?

A consistência é o que eu desejo, e Java deveria ter tanto suportado há estática de qualquer forma dentro de uma interface, ou ele deve ser consistente e permitir-lhes.

Foi útil?

Solução

Um proposta oficial foi feito para permitir métodos estáticos em interfaces de em Java 7. Esta proposta está sendo feita sob Projeto Coin .

A minha opinião pessoal é que é uma ótima idéia. Não há nenhuma dificuldade técnica na implementação, e é uma coisa muito lógico, razoável a fazer. Existem várias propostas no Project Coin que eu espero que não parte tornar-se da linguagem Java, mas este é um que poderia limpar um monte de APIs. Por exemplo, o classe Collections tem métodos estáticos para manipular qualquer implementação List; aqueles poderiam ser incluídos na interface List.


Atualização: Na Java Posse Podcast # 234, Joe D'arcy mencionou brevemente a proposta, dizendo que era "complexo" e provavelmente não iria fazê-lo em menos de Projeto Coin.


Atualização: Enquanto eles não fazê-lo em Projeto Coin para Java 7, Java 8 suporta funções estáticas em interfaces.

Outras dicas

Eu estou indo para ir com a minha teoria animal de estimação com este, que é que a falta de coerência neste caso é uma questão de conveniência, em vez de projeto ou necessidade, desde que eu ouvi não convincente argumento de que era tanto desses dois.

Os campos estáticos estão lá (a) porque eles estavam lá no JDK 1.0, e muitas decisões duvidosas foram feitas em JDK 1.0, e (b) campos finais estáticos em interfaces são a coisa java mais próximo teve a constantes no momento.

estáticos classes internas nas interfaces foram autorizados porque isso é açúcar sintático pura -. A classe interna não é realmente nada a ver com a classe pai

métodos Então estáticos não são permitidos simplesmente porque não há nenhuma razão para fazê-lo; consistência não é suficientemente forte para mudar o status quo.

Claro, isso poderia ser permitido em versões futuras JLS sem quebrar nada.

Nunca há um ponto de declarar um método estático em uma interface. Eles não podem ser executado pela chamada normal MyInterface.staticMethod (). (EDIT: Desde a última frase confundido algumas pessoas, chamando MyClass.staticMethod () executa precisamente a implementação de staticMethod em MyClass, que se MyClass é uma interface não pode existir) Se você chamá-los, especificando o MyImplementor.staticMethod classe implementando () então você deve saber a classe real, por isso é irrelevante se a interface contém ou não.

Mais importante, métodos estáticos nunca são substituídas, e se você tentar fazer:

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

as regras para dizer estática que o método definido no tipo declarado de var deve ser executado. Uma vez que esta é uma interface, isto é impossível.

Você pode, claro, sempre remover a palavra-chave estática do método. Tudo vai funcionar bem. Você pode ter que suprimir algumas advertências se for chamado a partir de um método de instância.

Para responder a alguns dos comentários abaixo, a razão que você não pode executar "resultado = MyInterface.staticMethod ()" é que ele teria que executar a versão do método definido no MyInterface. Mas não pode haver uma versão definida no MyInterface, porque é uma interface. Ele não tem código por definição.

O objetivo de interfaces é definir um contrato sem fornecer uma implementação. Portanto, você não pode ter métodos estáticos, porque eles teriam que ter uma implementação já na interface desde que você não pode substituir métodos estáticos. Quanto aos campos, única final fields estática são permitidos, que são, essencialmente, constantes (em 1.5+ você pode também têm enums nas interfaces). As constantes estão lá para ajudar a definir a interface sem números mágicos.

BTW, não há necessidade de especificar explicitamente modificadores static final para campos nas interfaces, porque os campos finais só estáticos são permitidos.

Esta é uma discussão antiga, mas isso é algo questão muito importante para todos. Desde que eu notei isso hoje só assim que eu estou tentando explicá-lo de forma mais limpa:

O principal objetivo da interface é fornecer algo que é unimplementable, por isso, se eles fornecem

métodos estáticos para ser permitido

então você pode chamar esse método usando interfaceName.staticMethodName () , mas este é um método não implementado e não contém nada. Por isso, é inútil para permitir métodos estáticos. Portanto, eles não fornecem tudo isso.

campos estáticos são permitidos

porque os campos não são implementáveis, por implementável i significa que você não pode executar qualquer operação lógica no campo, você pode fazer a operação no campo. Então você não está mudando o comportamento de campo que é por isso que eles são permitidos.

Classes internas são permitidos

Classes internas são permitidas porque digamos após a compilação do arquivo classe diferente da classe interna é criada InterfaceName $ InnerClassName.class , então basicamente você está fornecendo implementação na entidade diferente todos juntos, mas não na interface. Então implementação em Classes internas é fornecido.

Espero que isso ajudaria.

Na verdade, por vezes, existem razões que alguém pode se beneficiar de métodos estáticos. Eles podem ser usados ??como métodos de fábrica para as classes que implementam a interface. Por exemplo, que é a razão que tem interface de Recolha e a classe coleções em openjdk agora. Portanto, há soluções alternativas como sempre - fornecer uma outra classe com um construtor privado, que servirá como um "namespace" para os métodos estáticos

.

Antes de Java 5, um uso comum para os campos estáticos foi:

interface HtmlConstants {
    static String OPEN = "<";
    static String SLASH_OPEN = "</";
    static String CLOSE = ">";
    static String SLASH_CLOSE = " />";
    static String HTML = "html";
    static String BODY = "body";
    ...
}

public class HtmlBuilder implements HtmlConstants { // implements ?!?
    public String buildHtml() {
       StringBuffer sb = new StringBuffer();
       sb.append(OPEN).append(HTML).append(CLOSE);
       sb.append(OPEN).append(BODY).append(CLOSE);
       ...
       sb.append(SLASH_OPEN).append(BODY).append(CLOSE);
       sb.append(SLASH_OPEN).append(HTML).append(CLOSE);
       return sb.toString();
    }
}

Isto significava HtmlBuilder não tem que qualificar cada constante, para que ele pudesse usar Abrir em vez de HtmlConstants.OPEN

Usando implementos desta forma é em última análise, confundindo.

Agora com Java 5, temos a importação estática sintaxe para conseguir o mesmo efeito:

private final class HtmlConstants {
    ...
    private HtmlConstants() { /* empty */ }
}

import static HtmlConstants.*;
public class HtmlBuilder { // no longer uses implements
    ...
}

Não há nenhuma razão real para não ter métodos estáticos em interfaces exceto: os projetistas da linguagem Java não queria que fosse assim. Do ponto de vista técnico, faria sentido para permitir-lhes. Afinal uma classe abstrata pode tê-los também. Presumo mas não testá-lo, que você pode "mão ofício" código de byte em que a interface tem um método estático e deve IMHO trabalho sem problemas para chamar o método e / ou usar a interface como habitualmente.

Muitas vezes me pergunto por que métodos estáticos em tudo? Eles têm seus usos, mas os métodos de nível pacote / namespace provavelmente cobrir 80 do que métodos estáticos são usados.

duas razões principais vêm à mente:

  1. Os métodos estáticos em Java não pode ser substituída por subclasses, e este é um muito maior negócio para métodos que campos estáticos. Na prática, eu nunca sequer quis substituir um campo em uma subclasse, mas eu substituir métodos o tempo todo. Então, ter métodos estáticos impede que uma classe que implementa a interface de fornecer sua própria implementação desse método, que vence em grande parte o propósito de usar uma interface.

  2. Interfaces não são suposto ter código; isso é o que classes abstratas são para. O ponto inteiro de uma interface é para deixá-lo falar sobre objetos possivelmente não relacionadas que acontecerá a todos com um determinado conjunto de métodos. Na verdade, fornecendo uma implementação desses métodos está fora dos limites do que interfaces estão destinados a ser.

Os métodos estáticos são amarrados a uma classe. Em Java, uma interface não é tecnicamente uma classe, ele é um tipo, mas não uma classe (daí, a palavra-chave implementos e interfaces não se estendem Object). Porque interfaces são não classes, eles não podem ter métodos estáticos, porque não há nenhuma classe real para anexar a.

Você pode chamar InterfaceName.class para obter o objeto de classe correspondente à interface, mas a classe Classe afirma especificamente que representa classes e interfaces em um aplicativo Java. No entanto, a interface em si não é tratado como uma classe, e, portanto, você não pode anexar um método estático.

campos finais Apenas estáticas podem ser declaradas em uma interface (bem como métodos, que são públicos, mesmo se você não incluir a palavra-chave "pública", campos estáticos são "final" com ou sem a palavra-chave).

Estes são apenas valores, e serão copiadas literalmente onde quer que eles são usados ??em tempo de compilação, para que você nunca realmente "Call" campos estáticos em tempo de execução. Ter um método estático não teria a mesma semântica, já que envolveria chamar uma interface sem uma implementação, que Java não permite.

A razão é que todos os métodos definidos em uma interface são abstratos ou não declarar explicitamente que modificador. Um método estático resumo não é uma combinação permitida de modificadores desde métodos estáticos não são capazes de ser substituído.

Quanto ao porquê de interfaces permitem campos estáticos. Eu tenho um sentimento que deve ser considerado um "recurso". A única possibilidade que eu posso pensar seria a constantes de grupo que implementações da interface estaria interessado em.

Eu concordo que a consistência teria sido uma melhor abordagem. Não há membros estáticos deve ser permitido em uma interface.

Eu acredito que os métodos estáticos podem ser acessados ??sem a criação de um objeto e a interface não permite a criação de um objeto como restringir os programadores de usar os métodos de interface diretamente em vez da partir de sua classe implementada. Mas se você definir um método estático em uma interface, você pode acessá-lo diretamente, sem a sua implementação. Assim métodos estáticos não são permitidos nas interfaces. Eu não acho que a consistência deve ser uma preocupação.

método estático 1.8 interface de

Java é visível para métodos de interface única, se removermos o método () methodSta1 da classe InterfaceExample, não será capaz de usá-lo para o objeto InterfaceExample. No entanto, como outros métodos estáticos, podemos usar interface métodos estáticos usando nome da classe. Por exemplo, uma declaração válida será: exp1.methodSta1 ();

Assim, depois de olhar abaixo exemplo, podemos dizer: 1) Método de Java interface de estática é parte da interface, não podemos usá-lo para objetos de classe de implementação.

2) métodos de interface estáticos Java são bons para fornecer métodos de utilitário, por exemplo verificação nulo, coleção de classificação, registro etc.

3) método de interface estática Java nos ajuda no fornecimento de segurança, não permitindo que classes de implementação (InterfaceExample) para substituí-los.

4) Não podemos definir interface de método estático para métodos de classe Object, teremos compilador erro como “Este método estático não pode esconder o método de instância do objeto”. Isso é porque ele não é permitido em java, desde objeto é a classe base para todas as classes e não podemos ter método estático um nível de classe e outro método de instância com mesma assinatura.

5) Podemos usar java métodos de interface estáticos para remover classes de utilitários, como coleções e mover tudo isso de métodos estáticos para a interface correspondente, que seria fácil de encontrar e usar.

public class InterfaceExample implements exp1 {

    @Override
    public void method() {
        System.out.println("From method()");
    }

    public static void main(String[] args) {
        new InterfaceExample().method2();
        InterfaceExample.methodSta2();      //  <---------------------------    would not compile
        // methodSta1();                        //  <---------------------------    would not compile
        exp1.methodSta1();
    }

    static void methodSta2() {          //          <-- it compile successfully but it can't be overridden in child classes
        System.out.println("========= InterfaceExample :: from methodSta2() ======");
    }
}


interface exp1 {

    void method();
    //protected void method1();         //          <--      error
    //private void method2();           //          <--      error
    //static void methodSta1();         //          <--      error it require body in java 1.8

    static void methodSta1() {          //          <-- it compile successfully but it can't be overridden in child classes
        System.out.println("========= exp1:: from methodSta1() ======");
    }

    static void methodSta2() {          //          <-- it compile successfully but it can't be overridden in child classes
        System.out.println("========= exp1:: from methodSta2() ======");
    }

    default void method2() { System.out.println("---  exp1:: from method2() ---");}
    //synchronized default void method3() { System.out.println("---");}             // <-- Illegal modifier for the interface method method3; only public, abstract, default, static 
                                                                                // and strictfp are permitted
    //final default void method3() { System.out.println("---");} //             <--      error
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top