Classe interna dentro da interface

97

É possível criar uma classe interna dentro de uma interface?
Se for possível, por que queremos criar uma classe interna como essa, já que não vamos criar nenhum objeto de interface?

Essas classes internas ajudam em algum processo de desenvolvimento?

gmhk
fonte

Respostas:

51

Sim, você pode criar uma classe aninhada ou uma classe interna dentro de uma interface Java (observe que, ao contrário da crença popular, não existe uma " classe interna estática ": isso simplesmente não faz sentido, não há nada "interno" e não " classe externa "quando uma classe aninhada é estática, portanto não pode ser" interna estática ").

Enfim, o seguinte compila bem:

public interface A {
    class B {
    }
}

Já vi isso ser usado para colocar algum tipo de "verificador de contrato" diretamente na definição da interface (bem, na classe aninhada na interface, que pode ter métodos estáticos, ao contrário da própria interface, que não pode). Parecendo assim, se bem me lembro.

public interface A {
    static class B {
        public static boolean verifyState( A a ) {
            return (true if object implementing class A looks to be in a valid state)
        }
    }
}

Observe que não estou comentando sobre a utilidade de tal coisa, estou simplesmente respondendo à sua pergunta: isso pode ser feito e este é um tipo de uso que já vi fazer disso.

Agora, não vou comentar sobre a utilidade de tal construção e de eu vi: eu vi, mas não é uma construção muito comum.

Base de código 200KLOC aqui, onde isso acontece exatamente zero hora (mas temos muitas outras coisas que consideramos práticas ruins que acontecem exatamente zero vez também que outras pessoas achariam perfeitamente normal ...).

SintaxeT3rr0r
fonte
Você pode adicionar alguns exemplos de uso? Eu testei algo semelhante há algum tempo e não entendi o que posso ganhar usando essa construção.
Romano
@Roman: bem, lembro que encontrei isso em algum projeto (projeto relativamente limpo, eu acrescentaria, mas não eram meus), mas não sei se é realmente limpo ou não. Eu adicionei um pequeno exemplo que se parece com o que vi, mas mais uma vez: este não era o meu código e não estou usando essa construção, portanto não sou o mais qualificado para apresentar exemplos válidos :) IIRC a classe interna sempre foi nomeada, por exemplo, StateChecker e as chamadas sempre seriam semelhantes a: A.StateChecker.check (a) ou algo parecido.
SyntaxT3rr0r
8
Se você disser que “não existe uma" classe interna estática "”, sua resposta de que “você pode criar uma classe aninhada ou uma classe interna dentro de uma interface Java” está fundamentalmente errada. Usando sua definição restrita, interfaces não podem ter classes internas. Você pode omitir o staticmodificador de uma interfaceclasse aninhada, mas ainda assim, é uma classe aninhada, não uma classe interna.
Holger
6
Esta resposta está errada. As interfaces podem ter classes aninhadas estáticas, mas não classes internas.
Paul Boddington
1
@PaulBoddington Você está certo. Mesmo removendo 'estática', a Bclasse é uma classe aninhada estática e não uma classe interna; interfaces recebem tratamento especial. Não consegui encontrar menção a isso online, exceto nas próprias especificações: "Uma classe de membro de uma interface é implicitamente estática, portanto nunca é considerada uma classe interna." docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.1.3
Max Barraclough
109

Sim, podemos ter classes dentro de interfaces. Um exemplo de uso poderia ser

public interface Input
{
    public static class KeyEvent {
         public static final int KEY_DOWN = 0;
         public static final int KEY_UP = 1;
         public int type;
         public int keyCode;
         public char keyChar;
    }
    public static class TouchEvent {
         public static final int TOUCH_DOWN = 0;
         public static final int TOUCH_UP = 1;
         public static final int TOUCH_DRAGGED = 2;
         public int type;
         public int x, y;
         public int pointer;
    }
    public boolean isKeyPressed(int keyCode);
    public boolean isTouchDown(int pointer);
    public int getTouchX(int pointer);
    public int getTouchY(int pointer);
    public float getAccelX();
    public float getAccelY();
    public float getAccelZ();
    public List<KeyEvent> getKeyEvents();
    public List<TouchEvent> getTouchEvents();
}

Aqui, o código tem duas classes aninhadas que são para encapsular informações sobre objetos de evento que são posteriormente usados ​​em definições de método como getKeyEvents (). Tê-los dentro da interface de entrada melhora a coesão.

zafar142003
fonte
3
@Levit Apenas imaginando, como será a aparência da classe implementada?
overexchange
1
Adoraria ver uma implementação em ação para o uso acima. Obrigado.
Prakash K de
45

Um uso válido, IMHO, é definir objetos que são recebidos ou retornados pelos métodos de interface incluídos. Tipicamente estruturas de armazenamento de dados. Dessa forma, se o objeto for usado apenas para aquela interface, você tem as coisas de uma forma mais coesa.

Por exemplo:

interface UserChecker {
   Ticket validateUser(Credentials credentials);

   class Credentials {
      // user and password
   }

   class Ticket {
      // some obscure implementation
   }
}

Mas enfim ... é só uma questão de gosto.

Helios
fonte
35

Citação da especificação Java 7 :

As interfaces podem conter declarações de tipo de membro (§8.5).

Uma declaração de tipo de membro em uma interface é implicitamente estática e pública. É permitido especificar redundantemente um ou ambos os modificadores.

NÃO é possível declarar classes não estáticas dentro de uma interface Java, o que faz sentido para mim.

Nad Nik
fonte
Obrigado. Esta é provavelmente a resposta mais concisa de todas.
Joseph
1
Esta é a resposta que eu estava procurando .. mas o OP faz várias perguntas .. mesmo assim, tenho meu updoot.
Charlie Wallace
11

Um caso de uso interessante é fornecer uma espécie de implementação padrão para métodos de interface por meio de uma classe interna, conforme descrito aqui: https://stackoverflow.com/a/3442218/454667 (para superar o problema de herança de classe única).

Bachi
fonte
E é exatamente por isso que as classes-membro privadas fariam sentido.
Vincent
7

Certamente é possível, e um caso em que achei útil é quando uma interface precisa lançar exceções personalizadas. Você deve manter as exceções com sua interface associada, o que eu acho que geralmente é mais organizado do que encher sua árvore de origem com pilhas de arquivos de exceção triviais.

interface MyInterface {

   public static class MyInterfaceException extends Exception {
   }

   void doSomething() throws MyInterfaceException;
}
Michael Anderson
fonte
7

Sim, é possível ter definições de classes estáticas dentro de uma interface, mas talvez o aspecto mais útil desse recurso seja ao usar tipos de enum (que são tipos especiais de classes estáticas). Por exemplo, você pode ter algo assim:

public interface User {
    public enum Role {
        ADMIN("administrator"),
        EDITOR("editor"),
        VANILLA("regular user");

        private String description;

        private Role(String description) {
            this.description = description;
        }

        public String getDescription() {
            return description;
        }
    }

    public String getName();
    public void setName(String name);
    public Role getRole();
    public void setRole(Role role);
    ...
}
raspacorp
fonte
1

O que @Bachi menciona é semelhante a características em Scala e, na verdade, são implementadas usando uma classe aninhada dentro de uma interface. Isso pode ser simulado em Java. Veja também características de java ou padrão de mixins?

Henno Vermeulen
fonte
1

Talvez quando você quiser construções mais complexas, como alguns comportamentos de implementação diferentes, considere:

public interface A {
    public void foo();

    public static class B implements A {
        @Override
        public void foo() {
            System.out.println("B foo");
        }
    }
}

Esta é a sua interface e este será o implementee:

public class C implements A {
    @Override
    public void foo() {
        A.B b = new A.B();
        b.foo(); 
    }

    public static void main(String[] strings) {
        C c = new C();
        c.foo();
    }
}

Pode fornecer algumas implementações estáticas, mas isso não será confuso, não sei.

Ilian Zapryanov
fonte
0

Eu encontrei um uso para este tipo de construção.

  1. Você pode usar esta construção para definir e agrupar todas as constantes finais estáticas.
  2. Uma vez que é uma interface, você pode implementar isso em uma classe.

Você tem acesso a todas as constantes agrupadas; nome da classe atua como um namespace neste caso.

Venkat K
fonte
0

Você também pode criar classes estáticas "Helper" para funcionalidade comum para os objetos que implementam esta interface:

public interface A {
    static class Helper {
        public static void commonlyUsedMethod( A a ) {
           ...
        }
    }
}
Vencedor
fonte
0

Estou precisando de um agora. Eu tenho uma interface onde seria conveniente retornar uma classe única de vários de seus métodos. Essa classe só faz sentido como um contêiner para respostas de métodos dessa interface.

Portanto, seria conveniente ter uma definição de classe aninhada estática, que está associada apenas a esta interface, uma vez que esta interface deve ser o único lugar onde esta classe de contêiner de resultados é criada.

Mr.What
fonte
0

Por exemplo características (smth como interface com métodos implementados) em Groovy. Eles são compilados em uma interface que contém uma classe interna onde todos os métodos são implementados.

dehasi
fonte