it-swarm-pt.tech

Por que uma interface aninhada estática seria usada em Java?

Acabei de encontrar uma interface aninhada estática em nossa base de código.

class Foo {
    public static interface Bar {
        /* snip */
    }
    /* snip */
}

Eu nunca vi isso antes. O desenvolvedor original está fora de alcance. Portanto, tenho que perguntar SO:

Quais são as semânticas por trás de uma interface estática? O que mudaria se eu removesse o static? Por que alguém faria isso?

230
Mo.

A palavra-chave estática no exemplo acima é redundante (uma interface aninhada é automaticamente "estática") e pode ser removida sem efeito na semântica; Eu recomendaria que fosse removido. O mesmo vale para "public" em métodos de interface e "public final" em campos de interface - os modificadores são redundantes e apenas adicionam desordem ao código-fonte.

De qualquer maneira, o desenvolvedor está simplesmente declarando uma interface chamada Foo.Bar. Não há mais associação com a classe envolvente, exceto que o código que não pode acessar o Foo também não poderá acessar o Foo.Bar. (Do código-fonte - o bytecode ou o reflexo pode acessar o Foo.Bar mesmo que o Foo seja um pacote privado!)

É aceitável criar uma interface aninhada dessa forma, se você espera que ela seja usada apenas na classe externa, para que você não crie um novo nome de nível superior. Por exemplo:

public class Foo {
    public interface Bar {
        void callback();
    }
    public static void registerCallback(Bar bar) {...}
}
// ...elsewhere...
Foo.registerCallback(new Foo.Bar() {
    public void callback() {...}
});
290
Jesse Glick

A pergunta foi respondida, mas uma boa razão para usar uma interface aninhada é se sua função está diretamente relacionada à classe em que está. Um bom exemplo disso é um Listener. Se você tivesse uma classe Foo e quisesse que outras classes pudessem ouvir eventos nela, você poderia declarar uma interface chamada FooListener, o que é ok, mas provavelmente seria mais claro declarar uma interface aninhada e ter essas outras classes implementar Foo.Listener (uma classe aninhada Foo.Event não é ruim junto com isso).

71
ColinD

As interfaces de membros são implicitamente estáticas. O modificador estático do seu exemplo pode ser removido sem alterar a semântica do código. Veja também a especificação do idioma Java 8.5.1. Static Member Type Declarations

13
Bas Leijdekkers

Uma interface interna precisa ser estática para ser acessada. A interface não está associada a instâncias da classe, mas à própria classe, portanto, seria acessada com Foo.Bar, assim:

public class Baz implements Foo.Bar {
   ...
}

Na maioria das vezes, isso não é diferente de uma classe interna estática.

9
Clinton N. Dreisbach

A resposta de Jesse está próxima, mas acho que existe um código melhor para demonstrar porque uma interface interna pode ser útil. Veja o código abaixo antes de continuar lendo. Você consegue descobrir porque a interface interna é útil? A resposta é que a classe DoSomethingAlready pode ser instanciada com qualquer classe que implementa A e C; não apenas a classe concreta Zoo. Claro, isso pode ser alcançado mesmo se AC não for interno, mas imagine concatenar nomes mais longos (não apenas A e C), e fazer isso para outras combinações (digamos, A e B, C e B, etc.) e você facilmente Veja como as coisas saem do controle. Sem mencionar que as pessoas que revisam sua árvore de fontes serão sobrecarregadas por interfaces que são significativas somente em uma classe. Então, para resumir, uma interface interna permite a construção de tipos personalizados e melhora seu encapsulamento.

class ConcreteA implements A {
 :
}

class ConcreteB implements B {
 :
}

class ConcreteC implements C {
 :
}

class Zoo implements A, C {
 :
}

class DoSomethingAlready {
  interface AC extends A, C { }

  private final AC ac;

  DoSomethingAlready(AC ac) {
    this.ac = ac;
  }
}
6
user1982892

Para responder sua pergunta muito diretamente, veja Map.Entry.

Map.Entry

também isso pode ser útil

Entrada de blog Inerfaces aninhados estáticos

3
Henry B

Em 1998, Philip Wadler sugeriu uma diferença entre interfaces estáticas e interfaces não estáticas.

Até onde eu posso ver, a única diferença em fazer uma interface não-estática é que agora ela pode incluir classes internas não estáticas; Portanto, a alteração não tornaria inválidos os programas Javaexistentes.

Por exemplo, ele propôs uma solução para o Expression Problem , que é a incompatibilidade entre expressão como "o quanto a sua linguagem pode expressar" por um lado e a expressão como "os termos que você está tentando representar em sua língua "por outro lado.

Um exemplo da diferença entre interfaces aninhadas estáticas e não estáticas pode ser visto em seu código de exemplo :

// This code does NOT compile
class LangF<This extends LangF<This>> {
    interface Visitor<R> {
        public R forNum(int n);
    }

    interface Exp {
        // since Exp is non-static, it can refer to the type bound to This
        public <R> R visit(This.Visitor<R> v);
    }
}

Sua sugestão nunca foi feita emJava 1.5.0. Portanto, todas as outras respostas estão corretas: não há diferença para interfaces aninhadas estáticas e não estáticas.

0
Pindatjuh

Se você vai mudar a classe Foo na interface Foo a palavra-chave "pública" no exemplo acima também será redundante, porque

interface definida dentro de outra interface será implicitamente estática pública.

0
Danylo Volokh

Normalmente, vejo classes internas estáticas. Classes internas estáticas não podem referenciar as classes que contêm classes não estáticas. A menos que você esteja colidindo com algumas colisões de pacotes (já existe uma interface chamada Bar no mesmo pacote que o Foo) eu acho que seria o próprio arquivo. Também poderia ser uma decisão de design para impor a conexão lógica entre Foo e Bar. Talvez o autor pretendesse que o Bar fosse usado apenas com o Foo (embora uma interface interna estática não reforce isso, apenas uma conexão lógica)

0
basszero