2012-01-06 30 views
21

lectura código de otras personas, he visto un montón de:¿Por qué primero declaramos subtipos como su supertipo antes de crear una instancia de ellos?

List<E> ints = new ArrayList<E>(); 
Map<K, V> map = new HashMap<K, V>(); 

Mi pregunta es: ¿cuál es el punto/ventaja de ellos crear instancias de esa manera en lugar de:

ArrayList<E> ints = new ArrayList<E>(); 
HashMap<K, V> map = new HashMap<K, V>(); 

Lo que también hace extraño es que nunca he visto algo como:

CharSequence s = new String("String"); 

o

OutputStream out = new PrintStream(OutputStream); 


Duplicados (de la primera parte de la pregunta):

When/why to use/define an interface

Use interface or type for variable definition in java?

When should I use an interface in java?

why are interfaces created instead of their implementations for every class

What's the difference between these two java variable declarations?

Respuesta

24

¿Respuesta rápida? El uso de interfaces y superclases aumenta la portabilidad y la capacidad de mantenimiento de su código, principalmente al ocultar los detalles de la implementación. Tomemos el siguiente ejemplo hipotético:

class Account { 
    private Collection<Transaction> transactions; 

    public Account() { 
     super(); 
     transactions = new ArrayList<Transaction>(4); 
    } 

    public Collection<Transaction> getTransactions() { 
     return transactions; 
    } 
} 

He declarado un contrato para una cuenta que se afirma que las transacciones registradas en la cuenta pueden ser recuperados como una colección.Las personas que llaman de mi código no tienen que preocuparse por el tipo de colección que mi método realmente devuelve, y no deberían. Y eso me libera para cambiar la implementación interna si es necesario, sin impactar (alias romper) el número desconocido de clientes. Así a saber, si descubro que necesito para imponer algún tipo de singularidad en mis transacciones, puedo cambiar la aplicación se muestra arriba de un ArrayList a un HashSet, sin ningún impacto negativo sobre cualquier persona que utilice mi clase.

public Account() { 
    super(); 
    transactions = new HashSet<Transaction>(4); 
} 

En cuanto a su segunda pregunta, puedo decir que utiliza el principio de la portabilidad y la encapsulación dondequiera que tengan sentido. No hay una gran cantidad de implementaciones de CharSequence, y String es, con mucho, el más utilizado. Por lo tanto, no verá muchos desarrolladores que declaren variables de CharSequence en su código.

+0

Aceptando esto como la respuesta porque, si bien es también el más completo al proporcionar un ejemplo del mundo real, la segunda parte de mi pregunta se responde mejor aquí. – chrisdotcode

7

Para

List<E> ints = new ArrayList<E>(); 
Map<K, V> map = new HashMap<K, V>(); 

List y Map son las interfaces, por lo que cualquier clase que implementa las interfaces pueden ser asignados a estas referencias.

ArrayList es una de las varias clases (otra es LinkedList) que implementa la interfaz List.

Lo mismo con Map. HashMap, LinkedHashMap, TreeMap implementan Mapa.

Es un principio general Para programar para las interfaces y no para implementaciones. Debido a esto, la tarea de programación se vuelve más fácil. Puede cambiar dinámicamente el comportamiento de las referencias.

Si se escribe

ArrayList<E> ints = new ArrayList<E>(); 
HashMap<K, V> map = new HashMap<K, V>(); 

ints y map será ArrayList y HashMap solamente, para siempre.

2

Este (buen) estilo de declarar el tipo como el Interface que implementa la clase es importante porque nos obliga a utilizar métodos solo definidos en el Interface.

Como resultado, cuando tenemos que cambiar nuestras implementaciones de clase (es decir, nos encontramos con nuestra ArraySet es mejor que el estándar HashSet) tenemos la garantía de que si cambiamos la clase nuestro código funcionará porque ambas clases implementan la estricta impuesta por el Interface.

3

Esto se hace para asegurarse de que más tarde, cuando se trabaja con la variable que (o cualquier persona que utilice sus clases) no va a depender de métodos específicos para la aplicación elegida (ArrayList, HashMap, etc.)

1

Es simplemente es más fácil pensar en String como String. Así como es más fácil (y más beneficioso) pensar en WhateverList a partir del List.

Las bonificaciones se discuten muchas veces, pero en resumen, simplemente separe las preocupaciones: cuando necesita un CharSequence, lo usa. Es muy poco probable que necesite ArrayListsolo: por lo general, cualquier lista lo hará.

11

El uso de interfaces tiene la ventaja principal de que puede cambiar posteriormente la implementación (la clase) sin la necesidad de cambiar más que la única línea donde crea la instancia y realiza la asignación.

4

es un principio de diseño que program to the interface and not to the implementation.

De esa manera usted puede ofrecer más tarde una nueva aplicación a la misma interfaz.

desde el enlace anterior explica Erich Gamma:

Este principio es realmente acerca de las relaciones de dependencia que tienen que ser cuidadosamente manejado en una gran aplicación. Es fácil agregar una dependencia a una clase. Es casi demasiado fácil; simplemente agregue una declaración de importación y las herramientas modernas de desarrollo de Java como Eclipse incluso escriben esta declaración para usted. Curiosamente, lo inverso no es tan fácil y deshacerse de una dependencia no deseada puede ser un verdadero trabajo de refactorización o, lo que es peor, puede bloquear el reutilizar el código en otro contexto. Por esta razón, debe desarrollarse con los ojos abiertos cuando se trata de introducir dependencias. Este principio nos dice que dependiendo de una interfaz a menudo es beneficioso.

Aquí, el termin interface se refiere no sólo al artefacto Java, pero la interfaz pública de un objeto dado cuenta, que básicamente se compone de los métodos que tiene, así, podría ser una interfaz Java (como List en su ejemplo) o una superclase concreta.

Por lo tanto, en su ejemplo, si alguna vez desea utilizar un LinkedList, en su lugar sería más difícil porque el tipo ya está declarado como ArrayList cuando la lista solo hubiera sido suficiente.

Por supuesto, si necesita métodos específicos de una implementación determinada, debe declararlo de ese tipo.

Espero que esto ayude.

1

Cuando en algún momento decide utilizar una implementación diferente, dicen:

List<E> ints = new LinkedList<E>(); 

en lugar de

List<E> ints = new ArrayList<E>(); 

este cambio hay que hacer sólo en un solo lugar.

Existe el equilibrio adecuado de huelga:

normalmente se utiliza el tipo que le da las garantías más adecuados. Obviamente, un List es también un Collection que también es algo Iterable. Pero una colección no le da un orden , y un iterable no tiene un método "agregar".

El uso de ArrayList para el tipo de variable también es razonable, cuando quiere ser un poco más explícito sobre la necesidad de un acceso aleatorio rápido por posición del objeto; en una Lista Vinculada, un "get (100)" es mucho más lento. (Sería bueno si Java tenía una interfaz para esto, pero no creo que hay uno. Mediante el uso de ArrayList, que no permitir que emitan un array como lista.)

1
List<E> ints = new ArrayList<E>(); 

Si se escribe un código que ofertas solo con List, entonces funcionará para cualquier clase que implemente List (por ejemplo, LinkedList, etc.). Pero, si su código trata directamente con ArrayList, entonces está limitado a ArrayList.

CharSequence s = new String("String"); 

Manualmente instanciar un objeto String no es bueno. Deberías usar cadena literal en su lugar. Solo estoy adivinando la razón por la que no ve CharSequence porque es bastante nuevo y las cadenas son inmutables.

0

Esto está programando para la interfaz, no la implementación, según la Gang of Four. Esto ayudará a evitar que el código se vuelva dependiente de métodos que se agregan solo a implementaciones particulares, y facilita el cambio para usar una implementación diferente si es necesario por cualquier motivo, p. actuación.

3

La razón detrás de esto no es técnico, sino las cosas que hay que leer entre las líneas de código: Los List y Map ejemplos dice: "Sólo estoy interesado en cosas básicas lista/mapa, básicamente se puede utilizar cualquier cosa aquí ."Un ejemplo extremo de que sería

Iterable<Foo> items = new ArrayList<Foo>(); 

cuando en realidad sólo quiere hacer algunas cosas para cada cosa.

Como un beneficio adicional esto hace que sea un poco más fácil refactorizar el código más tarde en la utilidad común clases/métodos que no se requiera el tipo de hormigón. ¿O es que desea codificar el algoritmo varias veces para cada tipo de colección?

el String ejemplo, por el contrario, no se ve violentamente, porque a) String es de clase especial en Java: cada literal "foo" es automáticamente un String y tarde o temprano usted tiene para dar a los caracteres un método que solo acepta String yb) el CharSequence es realmente ahh mínimo. Ni siquiera es compatible con Unicode más allá del BMP correctamente y omite la mayoría de los métodos de consulta/manipulación de String.

4

@Bhushan respondieron por qué. para responder a sus confusiones Por qué nadie usa

CharSequence s = new String("String"); 

o

OutputStream out = new PrintStream(OutputStream); 

CharSequence incluye solamente algunos métodos comunes. Otras clases que implementan esta interfaz son principalmente búferes y solo String es inmutable. CharSequence define api común para las clases respaldadas por la matriz char y Esta interfaz no refina los contratos generales de los métodos iguales y hashCode (ver javadoc).

OutputStream es una API de bajo nivel para escribir datos. Porque PrintStreamagrega métodos más convenientes para escribir - mayor nivel de abstracción, se utiliza en OutputStream.

Cuestiones relacionadas