web-development-kb-es.site

¿Por qué se usaría una interfaz anidada estática en Java?

Acabo de encontrar una interfaz anidada estática en nuestra base de código.

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

Nunca he visto esto antes. El desarrollador original está fuera de alcance. Por lo tanto tengo que preguntar SO:

¿Cuáles son las semánticas detrás de una interfaz estática? ¿Qué cambiaría, si elimino la static? ¿Por qué alguien haría esto?

230
Mo.

La palabra clave estática en el ejemplo anterior es redundante (una interfaz anidada es automáticamente "estática") y puede eliminarse sin efecto en la semántica; Yo recomendaría que se elimine. Lo mismo se aplica a "público" en los métodos de interfaz y "final pública" en los campos de interfaz: los modificadores son redundantes y solo agregan desorden al código fuente.

De cualquier manera, el desarrollador simplemente está declarando una interfaz llamada Foo.Bar. No hay asociación adicional con la clase adjunta, excepto que el código que no puede acceder a Foo tampoco podrá acceder a Foo.Bar. (Desde el código fuente: ¡el código de bytes o la reflexión pueden acceder a Foo.Bar incluso si Foo es un paquete privado!)

Es un estilo aceptable crear una interfaz anidada de esta manera si espera que se use solo de la clase externa, de modo que no cree un nuevo nombre de nivel superior. Por ejemplo:

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

La pregunta ha sido respondida, pero una buena razón para usar una interfaz anidada es si su función está directamente relacionada con la clase en la que se encuentra. Un buen ejemplo de esto es una Listener. Si tuviera una clase Foo y quisiera que otras clases pudieran escuchar eventos, podría declarar una interfaz llamada FooListener, lo que está bien, pero probablemente sería más claro declarar una interfaz anidada y tener esas otras clases implementar Foo.Listener (una clase anidada Foo.Event no es mala junto con esto).

71
ColinD

Las interfaces de los miembros son implícitamente estáticas. El modificador estático en su ejemplo puede eliminarse sin cambiar la semántica del código. Ver también la Especificación del lenguaje Java 8.5.1. Declaraciones de tipo de miembro estático

13
Bas Leijdekkers

Una interfaz interna tiene que ser estática para poder acceder. La interfaz no está asociada con instancias de la clase, sino con la clase en sí, por lo que se accederá con Foo.Bar, así:

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

En la mayoría de los casos, esto no es diferente de una clase interna estática.

9

La respuesta de Jesse es cercana, pero creo que hay un mejor código para demostrar por qué una interfaz interna puede ser útil. Mira el código de abajo antes de seguir leyendo. ¿Puedes encontrar por qué la interfaz interna es útil? La respuesta es que la clase DoSomethingAlready se puede instanciar con alguna clase que implementa A y C; No solo la clase concreta del zoológico. Por supuesto, esto se puede lograr incluso si AC no es interno, pero imagínese concatenando nombres más largos (no solo A y C), y haciendo esto para otras combinaciones (por ejemplo, A y B, C y B, etc.) y fácilmente Mira cómo las cosas se salen de control. Sin mencionar que las personas que revisan su árbol de fuentes se verán abrumadas por las interfaces que son significativas solo en una clase. Para resumir, una interfaz interna permite la construcción de tipos personalizados y mejora su encapsulación..

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 a su pregunta de manera muy directa, consulte Map.Entry.

Mapa.Entrada

también esto puede ser útil.

Entrada estática del blog de Inerfaces anidadas

3
Henry B

En 1998, Philip Wadler sugirió una diferencia entre interfaces estáticas e interfaces no estáticas.

Por lo que puedo ver, la única diferencia en hacer que una interfaz no sea estática es que ahora puede incluir clases internas no estáticas; por lo que el cambio no invalidaría ningún programa Java existente.

Por ejemplo, propuso una solución al Problema de expresión , que es la falta de coincidencia entre la expresión como "cuánto puede expresar su idioma" por una parte y la expresión como "los términos que intenta representar en su idioma". por otra parte.

Un ejemplo de la diferencia entre interfaces anidadas estáticas y no estáticas se puede ver en su código de ejemplo :

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

Su sugerencia nunca se hizo en Java 1.5.0. Por lo tanto, todas las demás respuestas son correctas: no hay diferencia entre las interfaces anidadas estáticas y no estáticas.

0
Pindatjuh

Si cambia la clase Foo en la interfaz Foo, la palabra clave "pública" en el ejemplo anterior también será redundante porque

la interfaz definida dentro de otra interfaz será estáticamente implícitamente pública.

0
Danylo Volokh

Típicamente veo clases internas estáticas. Las clases internas estáticas no pueden hacer referencia a las clases contenidas, mientras que las clases no estáticas pueden. A menos que se encuentre con algunas colisiones de paquetes (ya existe una interfaz llamada Bar en el mismo paquete que Foo), creo que lo haría en su propio archivo. También podría ser una decisión de diseño para imponer la conexión lógica entre Foo y Bar. Tal vez el autor pretendía que Bar solo se usara con Foo (aunque una interfaz interna estática no aplicará esto, solo una conexión lógica)

0
basszero