2012-03-24 18 views
115

Duplicar posible:
Why should the interface for a Java class be prefered?Polimorfismo: ¿Por qué usar "List list = new ArrayList" en lugar de "ArrayList list = new ArrayList"?

cuándo debo usar

List<Object> list = new ArrayList<Object>(); 

ArrayList hereda de List, por lo que si algunas características en ArrayList no están en List, entonces yo Habrá perdido algunas de las características de ArrayList, ¿verdad? ¿Y el compilador notará un error al intentar acceder a estos métodos?

+0

Oh. Lo siento. porque cambio a 'objeto', así que lo olvido. – hqt

+6

@duffymo - Esa pregunta es preguntar por qué 'new List ()' no funciona. Es una pregunta completamente diferente. –

+2

No es una pregunta duplicada. El posible duplicado tiene una pregunta genérica pero un detalle específico. Encuentro que esta pregunta en el título es más relevante/en sincronización con lo que realmente se pregunta. – Dexters

Respuesta

205

La razón principal por la que harías esto es desacoplar tu código de una implementación específica de la interfaz. Cuando se escribe el código de la siguiente manera:

List list = new ArrayList(); 

el resto de su código sólo se sabe que los datos es de tipo List, lo cual es preferible, ya que le permite cambiar entre diferentes implementaciones de la interfaz List con facilidad.

Por ejemplo, supongamos que estaba escribiendo una biblioteca bastante grande de terceros, y diga que decidió implementar el núcleo de su biblioteca con un LinkedList.Si su biblioteca depende en gran medida del acceso a los elementos en estas listas, eventualmente descubrirá que ha tomado una mala decisión de diseño; se dará cuenta de que debería haber usado un ArrayList (que da O (1) el tiempo de acceso) en lugar de un LinkedList (que da O (n) el tiempo de acceso). Suponiendo que haya estado programando en una interfaz, hacer ese cambio es fácil. Sólo tendría que cambiar la instancia de List de,

List list = new LinkedList(); 

a

List list = new ArrayList(); 

y usted sabe que esto va a funcionar porque se ha escrito el código para seguir el contrato proporcionado por la interfaz List.

Por otro lado, si ha implementado el núcleo de su biblioteca usando LinkedList list = new LinkedList(), hacer un cambio así no sería tan fácil, ya que no hay garantía de que el resto de su código no haga uso de métodos específico para la clase LinkedList.

En general, la elección es simplemente una cuestión de diseño ... pero este tipo de diseño es muy importante (especialmente cuando se trabaja en proyectos grandes), ya que le permitirá realizar cambios específicos de la implementación más tarde sin romper código existente.

+4

explicación clara. :) – coder247

+44

Mucha gente no menciona que es perfectamente aceptable instanciarlo como una variable local a través de ArrayList list = new ArrayList(). Es realmente beneficioso utilizar la interfaz de la Lista en la firma del método o como el tipo de una variable de nivel de clase. ¿A quién le importa si tiene que regresar más tarde y cambiar la declaración del método local? Todo el beneficio se obtiene al exponer una Lista a otros métodos o bibliotecas, etc. – GreenieMeanie

+5

Es cierto, gracias por señalarlo. De hecho, ahora que lo pienso, probablemente hubiera tenido más sentido que diera un ejemplo desde el punto de vista de un cliente, en lugar de hacerlo él mismo. En ambos casos, usar 'List list = new ArrayList()' es una cuestión de garantizar que no se rompa el código existente. –

63

Esto se denomina programación para la interfaz. Esto será útil en caso de que desee pasar a alguna otra implementación de List en el futuro. Si quiere algunos métodos en ArrayList, entonces debería programar a la implementación que es ArrayList a = new ArrayList().

6

Esto le permite escribir algo como:

void doSomething() { 
    List<String>list = new ArrayList<String>(); 
    //do something 
} 

Más adelante, es posible que desee cambiar a:

void doSomething() { 
    List<String>list = new LinkedList<String>(); 
    //do something 
} 

sin tener que cambiar el resto del método.

Sin embargo, si desea utilizar un CopyOnWriteArrayList por ejemplo, lo que se necesita para declarar como tal, y no como una lista si desea utilizar sus métodos adicionales (addIfAbsent por ejemplo):

void doSomething() { 
    CopyOnWriteArrayList<String>list = new CopyOnWriteArrayList<String>(); 
    //do something, for example: 
    list.addIfAbsent("abc"); 
} 
+1

Según el comentario @GreenieMeanie de la respuesta aceptada, este cambio no importa ya que esta es una variable local. – Ram

5

Uso esa construcción cada vez que no deseo agregar complejidad al problema. Es solo una lista, no es necesario decir qué tipo de lista es, ya que no tiene importancia para el problema. A menudo utilizo Collection para la mayoría de mis soluciones, ya que, al final, la mayoría de las veces, para el resto del software, lo que realmente importa es el contenido que contiene, y no quiero agregar nuevos objetos a la Colección. .

Además, utiliza esa construcción cuando cree que es posible que desee cambiar la implementación de la lista que está utilizando. Digamos que estaba usando la construcción con una ArrayList, y su problema no era seguro para subprocesos. Ahora, desea que sea seguro para subprocesos, y para parte de su solución, cambie para usar un Vector, por ejemplo. En cuanto a los otros usos de esa lista, no importará si es una AraryList o un Vector, solo una Lista, no se necesitarán nuevas modificaciones.

2

En general, desea programar en una interfaz. Esto le permite intercambiar la implementación en cualquier momento. Esto es muy útil especialmente cuando te pasan una implementación que no conoces.

Sin embargo, hay ciertas situaciones en las que prefiere utilizar la implementación concreta. Por ejemplo, al serializar en GWT.

17

Esto también es útil al exponer una interfaz pública. Si usted tiene un método como este,

public ArrayList getList(); 

Entonces decide cambiar a,

public LinkedList getList(); 

Cualquier persona que estaba haciendo ArrayList list = yourClass.getList() tendrá que cambiar su código. Por otro lado, si lo hace,

public List getList(); 

Cambio de la aplicación no cambia nada para los usuarios de la API.

+0

yourClass.getList() supongo que es el caso de uso más práctico que he encontrado. Muchas gracias :) –

4

supongo que el núcleo de su pregunta es por qué a program to an interface, not to an implementation

Simplemente porque una interfaz le da más abstracción, y hace que el código más flexible y resistente a los cambios, porque se puede utilizar diferentes implementaciones de la misma interfaz (en este caso, es posible que desee cambiar la implementación de su Lista a una Lista enlazada en lugar de una Lista Array) sin cambiar su cliente.

10

Creo que la respuesta de @ tsatiz es en su mayoría correcta (programación en una interfaz en lugar de una implementación). Sin embargo, programando en la interfaz no perderá ninguna funcionalidad. Dejame explicar.

Si declara su variable como List<type> list = new ArrayList<type>, en realidad no pierde ninguna funcionalidad de de ArrayList.Todo lo que necesita hacer es enviar su list a ArrayList. He aquí un ejemplo:

List<String> list = new ArrayList<String>(); 
((ArrayList<String>) list).ensureCapacity(19); 

En última instancia creo tsatiz es correcta ya que una vez que lances a un ArrayList que ya no estés de codificación a una interfaz. Sin embargo, sigue siendo una buena práctica codificar inicialmente en una interfaz y, si luego es necesario, codificar una implementación si es necesario.

Espero que ayude!

+0

Este es muy fácil y claro. – CopsOnRoad

Cuestiones relacionadas