¿Quién extiende las interfaces? ¿Y por qué?


20

AFAIK, mi clase extends, clases e implementsinterfaces para padres . Pero me encuentro con una situación en la que no puedo usar implements SomeInterface. Es la declaración de un tipo genérico. Por ejemplo:

public interface CallsForGrow {...}

public class GrowingArrayList <T implements CallsForGrow>  // BAD, won't work!
                              extends ArrayList<T> 

Aquí el uso implementsestá sintácticamente prohibido. Primero pensé que está prohibido usar la interfaz dentro de <>, pero no. Es posible, solo tengo que usar en extendslugar de implements. Como resultado, estoy "extendiendo" una interfaz. Este otro ejemplo funciona:

public interface CallsForGrow {...}

public class GrowingArrayList <T extends CallsForGrow>  // this works!
                              extends ArrayList<T> 

A mí me parece una inconsistencia sintáctica. ¿Pero tal vez no entiendo algunas sutilezas de Java 6? ¿Hay otros lugares donde debería extender las interfaces? ¿Debería la interfaz, que quiero extender, tener algunas características especiales?

Respuestas:


25

En el caso de las variables de tipo genérico, al compilador no le importa si Tes una clase, una interfaz, una enumeración o una anotación. Lo único que le importa es que sea un tipo con un conjunto dado de subtipos y supertipos.

Y no hay ninguna razón para complicar la sintaxis solo porque en otro lugar (donde realmente implementa una interfaz) la distinción entre clases e interfaces es relevante (por ejemplo, si es implementuna interfaz, necesita implementar todos los métodos que define, pero usted no es necesario, si eres extenduna clase (no abstracta)).

Suponiendo por un momento que tendría que escribir implementsaquí, también necesitaría una sintaxis separada para los enumvalores (en lugar de simplemente escribir <E extends Enum<E>>) y anotaciones (que puede declarar fácilmente usando <A extends Annotation>).

El único lugar donde necesita escribir implementses en el punto donde realmente implementa la interfaz. En ese punto (y solo ese punto) la diferencia es importante, porque debe implementar los métodos definidos en la interfaz. Para todos los demás, no importa si alguno Aes una clase base o una interfaz implementada de B: es un supertipo y eso es todo lo que importa.

También tenga en cuenta que hay otro lugar donde lo usa extendscon las interfaces:

interface A {
}

interface B extends A {
}

En este punto implementsestaría mal, porque B no se implementa A .


Si usaremos su lógica, deberíamos usar 'extend SomeInterface' siempre , no solo en genéricos.
Gangnus

2
@Gangnus: no, porque para el implementador hay una diferencia concreta entre extendsy implements, es solo cuando se mira el problema desde una perspectiva pura del sistema de tipos, que no hay diferencia.
Joachim Sauer

1
Lo siento, no entiendo tu pensamiento. --1. ¿Por qué deberíamos usar "una perspectiva pura del sistema de tipos" en un caso y no en el otro? --2. ¿Por qué cambian las demandas sintácticas en estos diferentes lugares? ¿Podría explicarlo, por favor? En la respuesta, si es posible.
Gangnus

1
@Gangnus: ¿quién dice que Tes una clase? Tpodría hacer referencia a un tipo de interfaz o un enumtipo.
Joachim Sauer

1
viniendo de C #, toda esta discusión es ridícula. denotamos los supertipos de un tipo con :. y bajo las cubiertas, una interfaz es y siempre ha sido una clase abstracta con la restricción de contener solo abstractmiembros virtuales ( ) no implementados , para permitir la herencia múltiple. literalmente no hay diferencia entre implementsy extends. ambos podrían ser reemplazados por la misma palabra ( extends) o por algún símbolo arbitrario ( :) y no se perdería nada.
Sara

5

Cuando Java 5, y en particular los genéricos, se pusieron inicialmente a disposición de los desarrolladores que habían registrado un interés, la sintaxis era bastante diferente. En lugar de Set<? extends Foo>y Set<? super Bar>tenía Set<+Foo>y Set<-Foo>. Sin embargo, la respuesta fue que no estaba claro si +significaba más específico o más amplio (más clases) . Sun respondió a esa retroalimentación cambiando la sintaxis, pero dentro de la restricción de no introducir nuevas palabras clave, lo que habría sido un problema para la compatibilidad con versiones anteriores.

El resultado es que ninguno de los dos es bastante natural. Como observa, extendsestá sobrecargado para hablar de clases que "amplían" las interfaces, que no es el lenguaje utilizado en otros contextos; y superse sobrecarga para significar "es una superclase de", que es la dirección opuesta de la relación expresada previamente por la palabra clave, es decir, se refiere a una superclase.

Sin embargo, los fundamentos de lo que es una interfaz no se ven afectados por este cambio, y no introduce interfaces especiales que se extiendan de una manera nueva.


+1. Ya veo y estoy de acuerdo. Pero Joachim Sauer ha encontrado mi pensamiento erróneo de que T es necesariamente una clase. Entonces, la respuesta es suya. Su comprensión es una (o 2) planta más alta :-). Mi problema fue más primitivo. Gracias de todos modos por mi desarrollo.
Gangnus

2

Existen desventajas en permitir y prohibir dicha sintaxis, y las de permitir son mucho mayores.

Solo piensa en ello.

La separación de la interfaz y la implementación es uno de los modismos fundamentales de programación. Debido a eso, la sintaxis que permite deletrear "la interfaz implementa algo" sería tan mala como la que usa el signo más para denotar la multiplicación de operandos.


Okay. Entonces, realmente no entiendo algo. Lo consideré muy probable. Pero no has explicado el problema en absoluto, lo siento. T es una representación de una clase. ¿Por qué en un lugar uso extensiones T y en otros implementos T?
Gangnus

@Gangnus en el ejemplo que proporcionó T se refiere al parámetro de tipo que no es necesariamente una clase; vea lo que Joachim ya le dijo . Permitiendo que los implementos para que daría lugar a la misma lío he mencionado
mosquito

Sí, ya he visto su comentario. Se marcará como la respuesta cuando se ponga en respuesta. Hasta que ambos tengan mi agradecimiento y +1.
Gangnus

-1

Es necesario comprender la programación dirigida por la interfaz como el siguiente paso al comprender una interfaz. Indica cuál es el uso real de la interfaz. Qué papel juega en un programa Java (o cualquier otro lenguaje).


2
¿Cómo aborda su respuesta las preocupaciones del OP? Por favor, editar su respuesta a ser más clara.
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.