Clase interna dentro de la interfaz

97

¿Es posible crear una clase interna dentro de una interfaz?
Si es posible, ¿por qué querríamos crear una clase interna como esa ya que no vamos a crear ningún objeto de interfaz?

¿Estas clases internas ayudan en algún proceso de desarrollo?

gmhk
fuente

Respuestas:

51

Sí, puede crear tanto una clase anidada como una clase interna dentro de una interfaz Java (tenga en cuenta que, contrariamente a la creencia popular, no existe tal cosa como una " clase interna estática ": esto simplemente no tiene sentido, no hay nada "interno" y no " outter "cuando una clase anidada es estática, por lo que no puede ser" estática interna ").

De todos modos, lo siguiente se compila bien:

public interface A {
    class B {
    }
}

Lo he visto usado para poner algún tipo de "verificador de contrato" directamente en la definición de la interfaz (bueno, en la clase anidada en la interfaz, que puede tener métodos estáticos, al contrario que la propia interfaz, que no puede). Luciendo así si no recuerdo mal.

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

Tenga en cuenta que no estoy comentando sobre la utilidad de tal cosa, simplemente estoy respondiendo a su pregunta: se puede hacer y este es un tipo de uso que he visto que se le da.

Ahora no voy a comentar sobre la utilidad de tal construcción y por lo que he visto: lo he visto, pero no es una construcción muy común.

200KLOC codebase aquí donde esto sucede exactamente en el tiempo cero (pero luego tenemos muchas otras cosas que consideramos malas prácticas que suceden exactamente en el tiempo cero también que otras personas encontrarían perfectamente normales, así que ...).

Sintaxis T3rr0r
fuente
¿Puede agregar algunos ejemplos de uso? Probé algo similar hace algún tiempo y no he entendido qué puedo ganar con esta construcción.
Roman
@Roman: bueno, recuerdo que me encontré con esto en algún proyecto (un proyecto relativamente limpio agregaría pero no eran míos) pero no sé si está realmente limpio o no. Agregué un pequeño ejemplo que se parece a lo que he visto, pero una vez más: este no era mi código y no estoy usando esa construcción, por lo que no soy el más calificado para dar ejemplos válidos :) IIRC la clase dentro siempre fue nombrada, por ejemplo StateChecker y las llamadas siempre se verían así: A.StateChecker.check (a) o algo así.
Sintaxis T3rr0r
8
Si dice que “no existe tal cosa como una“ clase interna estática ””, su respuesta de que “ puede crear una clase anidada o una clase interna dentro de una interfaz Java” es fundamentalmente incorrecta. Usando su definición restringida, interfaces no puede tener clases internas. Puede omitir el staticmodificador de una interfaceclase anidada, pero aún así, es una clase anidada, no una clase interna.
Holger
6
Esta respuesta es incorrecta. Las interfaces pueden tener clases anidadas estáticas pero no clases internas.
Paul Boddington
1
@PaulBoddington Tienes razón. Incluso eliminando 'estática', la Bclase es una clase anidada estática y no una clase interna; las interfaces reciben un tratamiento especial. No pude encontrar una mención de esto en línea, excepto en la propia especificación: "Una clase miembro de una interfaz es implícitamente estática, por lo que nunca se considera una clase interna". docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.1.3
Max Barraclough
109

Sí, podemos tener clases dentro de interfaces. Un ejemplo de uso podría 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();
}

Aquí el código tiene dos clases anidadas que son para encapsular información sobre objetos de eventos que luego se usan en definiciones de métodos como getKeyEvents (). Tenerlos dentro de la interfaz de entrada mejora la cohesión.

zafar142003
fuente
3
@Levit Me pregunto, ¿cómo se verá la clase implementada?
sobreintercambio
1
Me encantaría ver una implementación en acción para el uso anterior. Gracias.
Prakash K
45

Un uso válido, en mi humilde opinión, es definir objetos que son recibidos o devueltos por los métodos de interfaz adjuntos. Normalmente, estructuras de almacenamiento de datos. De esa manera, si el objeto solo se usa para esa interfaz, tiene las cosas de una manera más cohesiva.

Por ejemplo:

interface UserChecker {
   Ticket validateUser(Credentials credentials);

   class Credentials {
      // user and password
   }

   class Ticket {
      // some obscure implementation
   }
}

Pero de todos modos ... es solo una cuestión de gustos.

helios
fuente
34

Cita de la especificación Java 7 :

Las interfaces pueden contener declaraciones de tipo de miembro (§8.5).

Una declaración de tipo de miembro en una interfaz es implícitamente estática y pública. Se permite especificar de forma redundante uno o ambos de estos modificadores.

NO es posible declarar clases no estáticas dentro de una interfaz Java, lo cual tiene sentido para mí.

Nad Nik
fuente
Gracias. Esta es probablemente la respuesta más concisa de todas.
Joseph
1
Esta es la respuesta que estaba buscando ... pero el OP hace varias preguntas ... de todos modos tengo mi updoot.
Charlie Wallace
11

Un caso de uso interesante es proporcionar una especie de implementación predeterminada para los métodos de interfaz a través de una clase interna como se describe aquí: https://stackoverflow.com/a/3442218/454667 (para superar el problema de la herencia de clase única).

Bachi
fuente
Y esta es exactamente la razón por la que las clases privadas para miembros tendrían sentido.
Vincent
7

Ciertamente es posible, y un caso en el que lo he encontrado útil es cuando una interfaz tiene que lanzar excepciones personalizadas. Usted conserva las excepciones con su interfaz asociada, que creo que a menudo es más ordenada que ensuciar su árbol de fuentes con montones de archivos de excepción triviales.

interface MyInterface {

   public static class MyInterfaceException extends Exception {
   }

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

Sí, es posible tener definiciones de clases estáticas dentro de una interfaz, pero quizás el aspecto más útil de esta característica es cuando se usan tipos de enumeración (que son clases especiales de clases estáticas). Por ejemplo, puede tener algo como esto:

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
fuente
1

Lo que @Bachi menciona es similar a los rasgos en Scala y en realidad se implementan usando una clase anidada dentro de una interfaz. Esto se puede simular en Java. ¿Ver también rasgos de Java o patrón de mixins?

Henno Vermeulen
fuente
1

Quizás cuando desee construcciones más complejas como algunos comportamientos de implementación diferentes, considere:

public interface A {
    public void foo();

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

Esta es su interfaz y esta será la implementada:

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

Puede proporcionar algunas implementaciones estáticas, pero no será confuso, no lo sé.

Ilian Zapryanov
fuente
0

Encontré un uso para este tipo de construcción.

  1. Puede utilizar esta construcción para definir y agrupar todas las constantes finales estáticas.
  2. Dado que es una interfaz, puede implementar esto en una clase.

Tiene acceso a todas las constantes agrupadas; El nombre de la clase actúa como un espacio de nombres en este caso.

Venkat K
fuente
0

También puede crear clases estáticas "Helper" para una funcionalidad común para los objetos que implementan esta interfaz:

public interface A {
    static class Helper {
        public static void commonlyUsedMethod( A a ) {
           ...
        }
    }
}
Víctor
fuente
0

Necesito uno ahora mismo. Tengo una interfaz en la que sería conveniente devolver una clase única de varios de sus métodos. Esta clase solo tiene sentido como contenedor para las respuestas de los métodos de esta interfaz.

Por lo tanto, sería conveniente tener una definición de clase anidada estática, que está asociada solo con esta interfaz, ya que esta interfaz debería ser el único lugar donde se crea esta clase de contenedor de resultados.

Señor que
fuente
0

Por ejemplo, rasgos (algo parecido a una interfaz con métodos implementados) en Groovy. Se compilan en una interfaz que contiene una clase interna donde se implementan todos los métodos.

dehasi
fuente