Respostas:
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 ...).
interface
s não podem ter classes internas. Você pode omitir o static
modificador de uma interface
classe aninhada, mas ainda assim, é uma classe aninhada, não uma classe interna.
B
classe é 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
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.
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.
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.
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).
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;
}
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);
...
}
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?
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.
Eu encontrei um uso para este tipo de construção.
Você tem acesso a todas as constantes agrupadas; nome da classe atua como um namespace neste caso.
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.
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.